[llvm-commits] PATCH: add new test tool: obj2yaml

Michael Spencer bigcheesegs at gmail.com
Sat Jun 9 02:44:51 PDT 2012


On Fri, Jun 8, 2012 at 11:09 AM, Marshall Clow <mclow.lists at gmail.com> wrote:
> [ resending to llvm-commits instead of -dev ]
>
> This patch adds a tool called 'obj2yaml', which takes an object file, and produces a YAML representation of the file.
> This is a companion tool to Michael Spencer's proposed "yaml2obj" tool.
>
> This tool processes only COFF files; the plan is to enhance it to handle other object formats, as well as object archives.
> The primary uses for this tool is expected to be:
>        1) Debugging object files that are produced by llvm and lld.
>        2) Automated testing suites.
>
> The goal is to have obj2yaml and yaml2obj be inverse operations, so that one can test either by using the other.
> So, both obj -> yaml -> obj and yaml -> obj -> yaml are expected to be idempotent.
>
> -- Marshall
>
> Marshall Clow     Idio Software   <mailto:mclow.lists at gmail.com>
>
> A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait).
>       -- Yu Suzuki

The design looks good, however there are quite a few LLVM style issues. The
major one that applies everywhere is that we use 2 spaces instead of tabs.
http://llvm.org/docs/CodingStandards.html#scf_spacestabs

Remaining comments are inline.

Index: utils/obj2yaml/obj2yaml.cpp
===================================================================
--- utils/obj2yaml/obj2yaml.cpp	(revision 0)
+++ utils/obj2yaml/obj2yaml.cpp	(revision 0)
@@ -0,0 +1,509 @@
+#include "llvm/ADT/OwningPtr.h"
+
+#include "llvm/Support/system_error.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "llvm/Object/Archive.h"
+
+#include <stdexcept>

No exceptions. http://llvm.org/docs/CodingStandards.html#ci_rtti_exceptions

+#include <fstream>
+#include <iostream>

http://llvm.org/docs/CodingStandards.html#ll_iostream

+#include <vector>
+#include <map>
+#include <cassert>
+#include <utility>

The includes are grouped correctly, but they should be sorted alphabetically
within each group. http://llvm.org/docs/CodingStandards.html#scf_includes

+//	Utility bits
+#define	ArrSize(x)	(sizeof(x)/sizeof(x[0]))

We have array_lengthof in ADT/STLExtras.h

+
+unsigned char printable ( unsigned char ch ) {

There should not be a space between printable and (. There should also not be
a space directly after ( and before ).
http://llvm.org/docs/CodingStandards.html#micro_spaceparen

Also all variables should start with an uppercase letter.
http://llvm.org/docs/CodingStandards.html#ll_naming

+	return ch >= ' ' && ch <= '~' ? ch : '.';
+	}

The } should not be indented.


+std::ostream& yaml_hex_stream ( std::ostream &out, const char *prefix,

This should be using raw_ostream.
http://llvm.org/docs/CodingStandards.html#ll_raw_ostream

This should be yamlHexStream.
http://llvm.org/docs/CodingStandards.html#ll_naming

Also the & should be on the right.

+						const unsigned char *data, std::size_t length ) {
+	const char *hex = "0123456789ABCDEF";
+	out << prefix << " !hex \"";
+	const unsigned char *p = data;
+	std::size_t len = length;
+	while ( len-- > 0 ) {
+		out << hex[( *p >> 4 ) & 0x0F] << hex[( *p & 0x0F )];
+		p++;
+		}
+
+	out << "\" # |";
+	p = data;
+	len = length;
+	while ( len-- > 0 )
+		out << printable ( *p++ );
+	out << "|" << std::endl;
+
+	return out;
+	}
+
+std::ostream& yaml_name ( std::ostream &out, const char *name,
std::size_t name_size ) {

80 colums. http://llvm.org/docs/CodingStandards.html#scf_codewidth

+	for ( std::size_t i = 0; i < name_size; ++i ) {
+		if ( !name[i] ) break;
+		out << name[i];
+		}
+	return out;
+	}
+
+template<typename T>
+T pointer_offset_cast ( T p, std::size_t offset ) {
+	return reinterpret_cast<T> ( reinterpret_cast<const char *> ( p ) + offset );
+}
+
+//	Given a map of <enum, const char *>, look up a value
+template <typename T>
+const char *name_lookup ( const std::map<T, const char *> &m, int val,
+											const char *not_found = NULL ) {
+	typename std::map<T, const char *>::const_iterator it
+									= m.find ( static_cast<T> ( val ));
+	return it != m.end () ? it->second : not_found;
+	}
+	
+
+namespace coff2yaml {

The content of a namespace should not be indented when it is this large.
http://llvm.org/docs/CodingStandards.html#micro_namespaceindent

+	using namespace llvm::COFF;
+
+	  enum {
+	  	OptionalHeaderSize     = 28
+	  	};
+
+	template <typename One, typename Two>
+	struct my_pair {
+		One first;
+		Two second;
+		};
+
+	#define	string_pair(x)	{x, #x}

Macros should be all uppercase. Although this has such a small scope I'm not
sure it matters.

+	static const my_pair<MachineTypes, const char *>
+	MachineTypePairs [] = {
+		string_pair(IMAGE_FILE_MACHINE_UNKNOWN),
+		string_pair(IMAGE_FILE_MACHINE_AM33),
+		string_pair(IMAGE_FILE_MACHINE_AMD64),
+		string_pair(IMAGE_FILE_MACHINE_ARM),
+		string_pair(IMAGE_FILE_MACHINE_ARMV7),
+		string_pair(IMAGE_FILE_MACHINE_EBC),
+		string_pair(IMAGE_FILE_MACHINE_I386),
+		string_pair(IMAGE_FILE_MACHINE_IA64),
+		string_pair(IMAGE_FILE_MACHINE_M32R),
+		string_pair(IMAGE_FILE_MACHINE_MIPS16),
+		string_pair(IMAGE_FILE_MACHINE_MIPSFPU),
+		string_pair(IMAGE_FILE_MACHINE_MIPSFPU16),
+		string_pair(IMAGE_FILE_MACHINE_POWERPC),
+		string_pair(IMAGE_FILE_MACHINE_POWERPCFP),
+		string_pair(IMAGE_FILE_MACHINE_R4000),
+		string_pair(IMAGE_FILE_MACHINE_SH3),
+		string_pair(IMAGE_FILE_MACHINE_SH3DSP),
+		string_pair(IMAGE_FILE_MACHINE_SH4),
+		string_pair(IMAGE_FILE_MACHINE_SH5),
+		string_pair(IMAGE_FILE_MACHINE_THUMB),
+		string_pair(IMAGE_FILE_MACHINE_WCEMIPSV2)
+		};
+	
+	static const my_pair<SectionCharacteristics, const char *>
+	SectionCharacteristicsPairs1 [] = {
+		string_pair(IMAGE_SCN_TYPE_NO_PAD),
+		string_pair(IMAGE_SCN_CNT_CODE),
+		string_pair(IMAGE_SCN_CNT_INITIALIZED_DATA),
+		string_pair(IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+		string_pair(IMAGE_SCN_LNK_OTHER),
+		string_pair(IMAGE_SCN_LNK_INFO),
+		string_pair(IMAGE_SCN_LNK_REMOVE),
+		string_pair(IMAGE_SCN_LNK_COMDAT),
+		string_pair(IMAGE_SCN_GPREL),
+		string_pair(IMAGE_SCN_MEM_PURGEABLE),
+		string_pair(IMAGE_SCN_MEM_16BIT),
+		string_pair(IMAGE_SCN_MEM_LOCKED),
+		string_pair(IMAGE_SCN_MEM_PRELOAD)
+		};
+	
+	static const my_pair<SectionCharacteristics, const char *>
+	SectionCharacteristicsPairsAlignment [] = {
+		string_pair(IMAGE_SCN_ALIGN_1BYTES),
+		string_pair(IMAGE_SCN_ALIGN_2BYTES),
+		string_pair(IMAGE_SCN_ALIGN_4BYTES),
+		string_pair(IMAGE_SCN_ALIGN_8BYTES),
+		string_pair(IMAGE_SCN_ALIGN_16BYTES),
+		string_pair(IMAGE_SCN_ALIGN_32BYTES),
+		string_pair(IMAGE_SCN_ALIGN_64BYTES),
+		string_pair(IMAGE_SCN_ALIGN_128BYTES),
+		string_pair(IMAGE_SCN_ALIGN_256BYTES),
+		string_pair(IMAGE_SCN_ALIGN_512BYTES),
+		string_pair(IMAGE_SCN_ALIGN_1024BYTES),
+		string_pair(IMAGE_SCN_ALIGN_2048BYTES),
+		string_pair(IMAGE_SCN_ALIGN_4096BYTES),
+		string_pair(IMAGE_SCN_ALIGN_8192BYTES)
+		};
+	
+	static const my_pair<SectionCharacteristics, const char *>
+	SectionCharacteristicsPairs2 [] = {
+		string_pair(IMAGE_SCN_LNK_NRELOC_OVFL),
+		string_pair(IMAGE_SCN_MEM_DISCARDABLE),
+		string_pair(IMAGE_SCN_MEM_NOT_CACHED),
+		string_pair(IMAGE_SCN_MEM_NOT_PAGED),
+		string_pair(IMAGE_SCN_MEM_SHARED),
+		string_pair(IMAGE_SCN_MEM_EXECUTE),
+		string_pair(IMAGE_SCN_MEM_READ),
+		string_pair(IMAGE_SCN_MEM_WRITE)
+		};
+		
+	static const my_pair<SymbolBaseType, const char *>
+	SymbolBaseTypePairs [] = {
+		string_pair(IMAGE_SYM_TYPE_NULL),
+		string_pair(IMAGE_SYM_TYPE_VOID),
+		string_pair(IMAGE_SYM_TYPE_CHAR),
+		string_pair(IMAGE_SYM_TYPE_SHORT),
+		string_pair(IMAGE_SYM_TYPE_INT),
+		string_pair(IMAGE_SYM_TYPE_LONG),
+		string_pair(IMAGE_SYM_TYPE_FLOAT),
+		string_pair(IMAGE_SYM_TYPE_DOUBLE),
+		string_pair(IMAGE_SYM_TYPE_STRUCT),
+		string_pair(IMAGE_SYM_TYPE_UNION),
+		string_pair(IMAGE_SYM_TYPE_ENUM),
+		string_pair(IMAGE_SYM_TYPE_MOE),
+		string_pair(IMAGE_SYM_TYPE_BYTE),
+		string_pair(IMAGE_SYM_TYPE_WORD),
+		string_pair(IMAGE_SYM_TYPE_UINT),
+		string_pair(IMAGE_SYM_TYPE_DWORD)
+		};
+	
+	static const my_pair<SymbolComplexType, const char *>
+	SymbolComplexTypePairs [] = {
+		string_pair(IMAGE_SYM_DTYPE_NULL),
+		string_pair(IMAGE_SYM_DTYPE_POINTER),
+		string_pair(IMAGE_SYM_DTYPE_FUNCTION),
+		string_pair(IMAGE_SYM_DTYPE_ARRAY),
+		};
+		
+	static const my_pair<SymbolStorageClass, const char *>
+	SymbolStorageClassPairs [] = {
+		string_pair(IMAGE_SYM_CLASS_END_OF_FUNCTION),
+		string_pair(IMAGE_SYM_CLASS_NULL),
+		string_pair(IMAGE_SYM_CLASS_AUTOMATIC),
+		string_pair(IMAGE_SYM_CLASS_EXTERNAL),
+		string_pair(IMAGE_SYM_CLASS_STATIC),
+		string_pair(IMAGE_SYM_CLASS_REGISTER),
+		string_pair(IMAGE_SYM_CLASS_EXTERNAL_DEF),
+		string_pair(IMAGE_SYM_CLASS_LABEL),
+		string_pair(IMAGE_SYM_CLASS_UNDEFINED_LABEL),
+		string_pair(IMAGE_SYM_CLASS_MEMBER_OF_STRUCT),
+		string_pair(IMAGE_SYM_CLASS_ARGUMENT),
+		string_pair(IMAGE_SYM_CLASS_STRUCT_TAG),
+		string_pair(IMAGE_SYM_CLASS_MEMBER_OF_UNION),
+		string_pair(IMAGE_SYM_CLASS_UNION_TAG),
+		string_pair(IMAGE_SYM_CLASS_TYPE_DEFINITION),
+		string_pair(IMAGE_SYM_CLASS_UNDEFINED_STATIC),
+		string_pair(IMAGE_SYM_CLASS_ENUM_TAG),
+		string_pair(IMAGE_SYM_CLASS_MEMBER_OF_ENUM),
+		string_pair(IMAGE_SYM_CLASS_REGISTER_PARAM),
+		string_pair(IMAGE_SYM_CLASS_BIT_FIELD),
+		string_pair(IMAGE_SYM_CLASS_BLOCK),
+		string_pair(IMAGE_SYM_CLASS_FUNCTION),
+		string_pair(IMAGE_SYM_CLASS_END_OF_STRUCT),
+		string_pair(IMAGE_SYM_CLASS_FILE),
+		string_pair(IMAGE_SYM_CLASS_SECTION),
+		string_pair(IMAGE_SYM_CLASS_WEAK_EXTERNAL),
+		string_pair(IMAGE_SYM_CLASS_CLR_TOKEN),
+		};
+
+	#undef string_pair
+	
+	class obj2yaml {
+	public:
+	
+		obj2yaml ( const char *contents, std::size_t size );
+		~obj2yaml () {}
+	
+		bool is_valid () const { return valid_; }
+		std::string error_message () const { return error_ ; }
+		std::ostream & write_yaml ( std::ostream &out );	// write the YAML
+	private:
+	//	Not implemented bits
+		obj2yaml ();	// default constructor
+		obj2yaml ( const obj2yaml & rhs ); // copy constructor
+		obj2yaml & operator = ( const obj2yaml & rhs ); // assignment
+		
+		std::ostream& write_symbols ( std::ostream &out,
+				const symbol *symbols, std::size_t numSymbols );
+
+		std::ostream& write_section ( std::ostream &out, const section &sect,
+				const unsigned char *sectionData, std::size_t sectionDataLength,
+				const relocation *relocations, std::size_t numRelocations );
+	
+		template <typename T>
+		T offset_cast ( std::size_t offset ) {
+			return reinterpret_cast<T> ( data_ + offset );
+			}
+		
+		const char * 		data_;			// the data we're parsing
+		const std::size_t	data_size_;		// size of the data
+		bool valid_;
+		std::string error_;		// if we failed to validate, what happened
+		const header *		header_;		// the file header
+		std::vector<section> section_headers_;
+		std::size_t string_table_size_;
+		const char *string_table_;
+	
+	//	Maps for lookup
+		static bool maps_made;
+		static std::map<MachineTypes, const char *> MachineTypeNames;
+		static std::map<SectionCharacteristics, const char *>
SectionCharacteristicNamesAlignment;
+		static std::map<SymbolBaseType, const char *> SymbolBaseTypeNames;
+		static std::map<SymbolComplexType, const char *> SymbolComplexTypeNames;
+		static std::map<SymbolStorageClass, const char *> SymbolStorageClassNames;
+
+		static void make_maps ();
+		};
+	
+	bool obj2yaml::maps_made = false;
+	std::map<MachineTypes,           const char *> obj2yaml::MachineTypeNames;
+	std::map<SectionCharacteristics, const char *>
obj2yaml::SectionCharacteristicNamesAlignment;
+	std::map<SymbolBaseType,         const char *> obj2yaml::SymbolBaseTypeNames;
+	std::map<SymbolComplexType,      const char *>
obj2yaml::SymbolComplexTypeNames;
+	std::map<SymbolStorageClass,     const char *>
obj2yaml::SymbolStorageClassNames;
+	
+//	Build a map from a sequence of pairs
+	template<typename T>
+	void build_map ( std::map<T, const char *> &m,
+			const my_pair<T, const char *> *ptr, std::size_t count ) {
+		for ( std::size_t i = 0; i < count; ++i, ptr++ )
+			m [ ptr->first ] = ptr->second;
+		}
+		
+	void obj2yaml::make_maps () {
+	//	I'd rather that these were static_assert
+		assert ( sizeof ( header ) == HeaderSize );
+		assert ( sizeof ( section ) == SectionSize );
+	//	Using clang on MacOS, these are not true

This is bad.

+	//	assert ( sizeof ( symbol ) == SymbolSize );
+	//	assert ( sizeof ( relocation ) == RelocationSize );
+
+		build_map ( MachineTypeNames,
+					MachineTypePairs, ArrSize(MachineTypePairs));
+		build_map ( SectionCharacteristicNamesAlignment,
+					SectionCharacteristicsPairsAlignment,
+					ArrSize(SectionCharacteristicsPairsAlignment));
+		build_map ( SymbolBaseTypeNames,
+					SymbolBaseTypePairs, ArrSize(SymbolBaseTypePairs));
+		build_map ( SymbolComplexTypeNames,
+					SymbolComplexTypePairs, ArrSize(SymbolComplexTypePairs));
+		build_map ( SymbolStorageClassNames,
+					SymbolStorageClassPairs, ArrSize(SymbolStorageClassPairs));
+
+		maps_made = true;
+		}
+	
+/*
+	My preferred solution here would be to throw a std::runtime_error that
+	contained the string describing the error that occurred. However, exceptions
+	are disabled in llvm code. So, instead, we just set a boolean 'is_valid' and
+	save the error message for the client to retrieve.
+	In any case, the object is always left in a destructible state.
+*/
+	obj2yaml::obj2yaml ( const char *contents, std::size_t size ) :
+			data_ ( contents ), data_size_ ( size ),
+			valid_ ( false ),  string_table_size_(0), string_table_ (NULL) {
+		
+	//	One time init; not thread safe
+		if ( !maps_made )
+			make_maps ();
+		
+		if ( data_size_ < HeaderSize )
+			{ error_ = "File too small" ; return ; }
+			
+	//	validate the header
+		header_ = offset_cast<const header *> ( 0 );	// header is at the start
+		if ( header_->SizeOfOptionalHeader != 0

This is using llvm::COFF::header which does not handle endianess. This code is
incorrect on big endian machines. The structs from llvm/Object/COFF.h should be
used instead. They are designed for this purpose.

+						&& header_->SizeOfOptionalHeader != OptionalHeaderSize )
+			{ error_ = "Bad optional header size" ; return ; }
+		if ( header_->PointerToSymbolTable >= data_size_ )
+			{ error_ = "Symbol table offset too big" ; return ; }
+					
+	//	Make sure that there's enough room in the file for the section
headers, and read them.
+		if ( header_->SizeOfOptionalHeader + HeaderSize +
(header_->NumberOfSections * SectionSize) > data_size_ )
+			{ error_ = "File too small for section headers" ; return ; }
+
+	//	Advance past the headers
+		std::size_t section_offset = HeaderSize + header_->SizeOfOptionalHeader;
+		for ( uint32_t i = 0; i < header_->NumberOfSections; ++i ) {
+			const section *s = offset_cast<const section *> ( section_offset +
( i * SectionSize ));
+			if ( s->PointerToRawData + s->SizeOfRawData > data_size_ )
+				{ error_ = "Section header RawData too large" ; return ; }
+			if ( s->PointerToRelocations > data_size_ )
+				{ error_ = "Section header PointerToRelocations too large" ; return ; }
+			if ( s->PointerToLineNumbers > data_size_ )
+				{ error_ = "Section header PointerToLineNumbers too large" ; return ; }
+			section_headers_.push_back ( *s );
+			}
+	
+	//	Make sure the string table is a valid size, and read it.
+		std::size_t stringTableOffset = header_->PointerToSymbolTable
+								+ header_->NumberOfSymbols * SymbolSize;
+		if ( stringTableOffset > data_size_ )
+			{ error_ = "Non-existant string table" ; return ; }
+		
+		string_table_size_ = data_size_ - stringTableOffset;
+		string_table_ = offset_cast<const char *> ( stringTableOffset );
+		valid_ = true;
+		}		
+				
+	
+	std::ostream& obj2yaml::write_section ( std::ostream &out, const
section &sect,
+			const unsigned char *sectionData, std::size_t sectionDataLength,
+			const relocation *relocations, std::size_t numRelocations ) {
+		const my_pair<SectionCharacteristics, const char *> *ptr;	
+		
+		out << "  - !Section" << std::endl;
+		out << "    Name: ";
+		yaml_name ( out, sect.Name, NameSize ) << std::endl;
+	
+		out << "    Characteristics: [";
+		for ( ptr = SectionCharacteristicsPairs1;
+				ptr != SectionCharacteristicsPairs1 + ArrSize
(SectionCharacteristicsPairs1); ++ptr )
+			if ( ptr->first & sect.Characteristics )
+				out << ptr->second << ", ";
+				
+		out << name_lookup ( SectionCharacteristicNamesAlignment,
+				sect.Characteristics & 0x00F00000, "#
Unrecognized_IMAGE_SCN_ALIGN" ) << ", ";
+	
+		for ( ptr = SectionCharacteristicsPairs2;
+				ptr != SectionCharacteristicsPairs2 + ArrSize
(SectionCharacteristicsPairs2); ++ptr )
+			if ( ptr->first & sect.Characteristics )
+				out << ptr->second << ", ";
+	
+		out << "] # 0x" << sect.Characteristics << std::endl;
+		yaml_hex_stream ( out, "    SectionData: ", sectionData, sectionDataLength );
+		out << std::endl;
+		if ( numRelocations > 0 ) {
+			out << "    Relocations: " << std::endl;
+			for ( std::size_t i = 0; i < numRelocations; ++i ) {
+				const relocation *p = pointer_offset_cast<const relocation *> (
relocations, i * RelocationSize );
+				out << "      - !Relocation" << std::endl;
+				out << "        VirtualAddress: "   << p->VirtualAddress   <<
std::endl;	// hex!
+				out << "        SymbolTableIndex: " << p->SymbolTableIndex << std::endl;
+				out << "        Type: " << std::endl;
+				out << std::endl;
+				}
+			}	
+		return out;
+		}
+	
+	std::ostream& obj2yaml::write_symbols ( std::ostream &out, const
symbol *symbols, std::size_t numSymbols ) {
+		out << "symbols:" << std::endl;
+		for ( std::size_t i = 0; i < numSymbols; ++i ) {
+			const symbol *p = pointer_offset_cast<const symbol *> ( symbols, i
* SymbolSize );
+			out << "  - !Symbol" << std::endl;
+			out << "    Name: ";
+			if (0 != p->Name[0])	// the name is inline
+				yaml_name ( out, p->Name, NameSize ) << std::endl;
+			else {	// the name is in the string table
+				uint32_t offset = *reinterpret_cast<const uint32_t *> (p->Name + 4);
+				out << string_table_ + offset << std::endl;	// D'oh!
+				}
+			out << "    Value: "         << p->Value << std::endl;
+			out << "    SectionNumber: " << (int) p->SectionNumber << std::endl;
+	//		out << "    Type: "          << (int) p->Type << std::endl;
+			std::size_t  simpleType = p->Type & 0x0F;	// LSB of type
+			std::size_t complexType = ( p->Type >> 8 ) & 0x0F;	// MSB of type
+	
+			out << "    SimpleType: "
+				<< name_lookup ( SymbolBaseTypeNames, simpleType, "#
Unknown_SymbolBaseType" )
+				<< " # (" << simpleType  << ")" << std::endl;
+			out << "    ComplexType: "
+				<< name_lookup ( SymbolComplexTypeNames, complexType, "#
Unknown_SymbolComplexType" )
+				<< " # (" << simpleType  << ")" << std::endl;
+			out << "    StorageClass: "
+				<< name_lookup ( SymbolStorageClassNames,  p->StorageClass, "#
Unknown_StorageClass" )
+				<< " # (" << (int) p->StorageClass  << ")" << std::endl;
+	
+		//	out << "    StorageClass: "  << (int) p->StorageClass << std::endl;
+			if ( p->NumberOfAuxSymbols > 0 ) {
+				out << "    NumberOfAuxSymbols: " << (int) p->NumberOfAuxSymbols
<< std::endl;
+				yaml_hex_stream ( out, "    AuxillaryData: ",
+					reinterpret_cast<const unsigned char*> (p) + SymbolSize, SymbolSize );
+				++i;	// skip the next one
+				}
+				
+			out << std::endl;
+			}
+	
+		return out;
+		}
+	
+	
+	std::ostream & obj2yaml::write_yaml ( std::ostream &out ) {
+		out << std::hex << std::uppercase;
+	//	Dump out the header
+		out << "header: !Header" << std::endl;
+		out << "  Machine: ";
+		out << name_lookup ( MachineTypeNames, header_->Machine, "#
Unknown_MachineTypes" );
+		out << " # (0x" << header_->Machine << ")" << std::endl << std::endl;
+	
+	//	Dump out the sections
+		out << "sections:" << std::endl;
+		for ( std::vector<section>::const_iterator iter = section_headers_.begin ();
+				iter != section_headers_.end (); ++iter ) {
+	//		std::cout << "## -> There are " << iter->SizeOfRawData << "
bytes of raw data and " << iter->NumberOfRelocations << " relocations"
<< std::endl;
+			
+			const unsigned char *sectionData = offset_cast<const unsigned char
*> ( iter->PointerToRawData );
+			const relocation *relocationData = offset_cast<const relocation *>
   ( iter->PointerToRelocations );
+			this->write_section ( out, *iter, sectionData,
+						iter->SizeOfRawData, relocationData, iter->NumberOfRelocations );
+			}
+	
+	//	Read and dump out the symbols
+		const symbol *symbolData = offset_cast<const symbol *> (
header_->PointerToSymbolTable );
+		this->write_symbols ( out, symbolData, header_->NumberOfSymbols );
+	
+		return out;
+		}
+
+	}	// end of namespace coff
+
+
+using namespace llvm;
+
+enum ObjectFileType { coff } ;
+
+cl::opt<ObjectFileType> InputFormat(
+	cl::desc("Choose input format"),
+		cl::values (
+			clEnumVal ( coff, "process COFF object files" ),
+		clEnumValEnd ));
+		
+cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input
file>"), cl::init("-"));
+
+int main ( int argc, char * argv[] ) {
+	cl::ParseCommandLineOptions(argc, argv);
+	sys::PrintStackTraceOnErrorSignal();
+	PrettyStackTraceProgram X(argc, argv);
+	llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
+
+//	Process the input file	
+	OwningPtr<MemoryBuffer> buf;
+	error_code ec = MemoryBuffer::getFile ( InputFilename, buf, -1, false );

This should be getFileOrSTDIN.

+
+//	TODO: If this is an archive, then burst it and dump each entry
+	if ( ec != error_code::success ())

This can just be if (ec). Or better yet, if (error_code ec =
MemoryBuffer::getFileOrSTDIN(...))

+		std::cerr << "Can't open file '" << InputFilename << "' for
reading" << std::endl;

This should print out the error given by ec.

+	else {
+		coff2yaml::obj2yaml coff ( buf->getBufferStart (), buf->getBufferSize ());
+		if ( coff.is_valid ())
+			coff.write_yaml ( std::cout );
+		else {
+			std::cerr << "## Error reading/parsing '" << InputFilename << "'"
<< std::endl;
+			std::cerr << "   Message: '" << coff.error_message () << "'" << std::endl;
+			}
+		}
+		
+	return 0;
+	}

- Michael Spencer




More information about the llvm-commits mailing list