diff options
Diffstat (limited to 'test/libelf/tset/bin/elfc')
-rwxr-xr-x | test/libelf/tset/bin/elfc | 1615 |
1 files changed, 1615 insertions, 0 deletions
diff --git a/test/libelf/tset/bin/elfc b/test/libelf/tset/bin/elfc new file mode 100755 index 0000000000000..99fa859f5a68f --- /dev/null +++ b/test/libelf/tset/bin/elfc @@ -0,0 +1,1615 @@ +#!/usr/bin/env python +# +# This script converts a textual (YAML) description of an ELF file to +# an equivalent 'binary' file. +# +# The YAML description may have the following top-level keys: +# +# 'elf_fillchar': char +# Sets the fill character to 'char'. +# 'ehdr': EHDR-DESCRIPTOR +# Defines an ELF Ehdr structure. +# 'phdrtab': list-of(PHDR-DESCRIPTOR) +# Defines the contents of the ELF Program Header table. +# Each `Phdr' descriptor represents one ELF Phdr entry. +# 'sections': list-of(SECTION-DESCRIPTOR) +# Defines the content of each section in the file. Each +# `SECTION-DESCRIPTOR' contains information for the +# section `header' and the actual data for the section. +# +# The script will compute reasonable defaults for any fields +# left unspecified in the YAML description. +# +# Descriptors EHDR-DESCRIPTOR and PHDR-DESCRIPTOR may be specified +# as a YAML key-value set. The key names correspond to the +# field names of the corresponding ELF structures, e.g., 'e_machine' +# and 'e_ident' for the Ehdr and 'p_type' and 'p_paddr' for +# a Phdr entry. +# +# Descriptor SECTION-DESCRIPTOR contains the fields in an ELF +# Shdr structure and an additional member 'sh_data', whose +# value is the data for the section. +# +# Example: +# +# <snip> +# ehdr: !Ehdr +# e_ident: !Ident +# ei_class: ELFCLASS32 +# ei_data: ELFDATA2MSB +# e_machine: EM_PPC +# phdrtab: +# - !Phdr +# ph_type: PHT_NULL +# ... other program header fields ... +# - !Phdr +# ... etc. ... +# sections: +# - !Section +# sh_name: .dynsym +# ... other section header fields ... +# sh_data: # ... list of data ... +# - !Dyn +# d_tag: 0xdeadcode +# - !Dyn +# d_tag: 0xcafebabe +# - !Section +# sh_name: .shstrtab +# sh_type: SHT_STRTAB +# sh_data: +# - string1 +# - string2 +# </snip> +# +# :: Handling of strings :: +# +# Fields like 'sh_name' (in a section header) are defined to contain +# an integer index into a specified string table (in this case a +# section with name '.shstrtab'). Other ELF data structures use a +# similar convention; names in a '.dynamic' section as stored as +# indices into a '.dynstr' section. In the YAML descriptor, such +# fields may be specified as indices, which are used as-is, or as text +# strings which are converted to the appropriate string index. +# For convenience in creating ELF objects with a large number of +# sections, a section index may be manually specified using a +# 'sh_index' pseudo field. +# +# $Id: elfc 1718 2011-08-12 07:30:43Z jkoshy $ + +version = "%prog 1.0" +usage = "usage: %prog [options] [input-file]" +description = """Create an ELF binary from a textual description in """ + \ + """'input-file' (or stdin)""" + +import optparse, re, struct, sys, types, yaml + +class ElfError(Exception): + """An exception signalled during conversion.""" + + def __init__(self, node=None, msg=None): + """Initialize an exception object. + + Arguments: + node -- a YAML parse tree node. + msg -- human readable message associated with this + exception. + """ + if node: + self.ee_start = node.start_mark.line + 1 + self.ee_end = node.end_mark.line + 1 + else: + self.ee_start = self.ee_end = -1 + self.ee_msg = msg + + def __str__(self): + """Form a printable representation of an exception.""" + + if self.ee_start != -1: + if self.ee_start == self.ee_end: + return "Error: line %d: %s" % (self.ee_start, + self.ee_msg) + else: + return "Error: lines %d--%d: %s" % \ + (self.ee_start, self.ee_end, + self.ee_msg) + else: + return "Error: %s" % self.ee_msg + + +# +# Mappings used by the 'encode()' function +# + +elf_cap_tag = { + 'CA_SUNW_NULL': 0, 'CA_SUNW_HW_1': 1, 'CA_SUNW_SF_1': 2 +} + +elf_d_flags = { + 'DF_ORIGIN': 0x0001, 'DF_SYMBOLIC': 0x0002, 'DF_TEXTREL': 0x0004, + 'DF_BIND_NOW': 0x0006, 'DF_STATIC_TLS': 0x0010 +} + +elf_d_tag = { + # from <sys/elf_common.h> + 'DT_NULL': 0, 'DT_NEEDED': 1, 'DT_PLTRELSZ': 2, 'DT_PLTGOT': 3, + 'DT_HASH': 4, 'DT_STRTAB': 5, 'DT_SYMTAB': 6, 'DT_RELA': 7, + 'DT_RELASZ': 8, 'DT_RELAENT': 9, 'DT_STRSZ': 10, 'DT_SYMENT': 11, + 'DT_INIT': 12, 'DT_FINI': 13, 'DT_SONAME': 14, 'DT_RPATH': 15, + 'DT_SYMBOLIC': 16, 'DT_REL': 17, 'DT_RELSZ': 18, 'DT_RELENT': 19, + 'DT_PLTREL': 20, 'DT_DEBUG': 21, 'DT_TEXTREL': 22, 'DT_JMPREL': 23, + 'DT_BIND_NOW': 24, 'DT_INIT_ARRAY': 25,'DT_FINI_ARRAY': 26, + 'DT_INIT_ARRAYSZ': 27, 'DT_FINI_ARRAYSZ': 28, 'DT_RUNPATH': 29, + 'DT_FLAGS': 30, 'DT_ENCODING': 32, 'DT_PREINIT_ARRAY': 32, + 'DT_PREINIT_ARRAYSZ': 33, 'DT_LOOS': 0x6000000d, 'DT_HIOS': 0x6ffff000, + 'DT_LOPROC': 0x70000000, 'DT_HIPROC': 0x7fffffff, + 'DT_SUNW_AUXILIARY': 0x6000000D, 'DT_SUNW_RTLDINF': 0x6000000E, + 'DT_SUNW_FILTER': 0x6000000F, 'DT_SUNW_CAP': 0x60000010, + # from "usr.bin/elfdump/elfdump.c" + 'DT_GNU_PRELINKED': 0x6ffffdf5, 'DT_GNU_CONFLICTSZ': 0x6ffffdf6, + 'DT_GNU_LIBLISTSZ': 0x6ffffdf7, 'DT_SUNW_CHECKSUM': 0x6ffffdf78, + 'DT_PLTPADSZ': 0x6ffffdf79, 'DT_MOVEENT': 0x6ffffdfa, + 'DT_MOVESZ': 0x6ffffdfb, 'DT_FEATURE': 0x6ffffdfc, + 'DT_FEATURE': 0x6ffffdfd, 'DT_POSFLAG_1': 0x6ffffdfe, + 'DT_SYMINENT': 0x6ffffdff, 'DT_VALRNGHI': 0x6ffffdff, # dup + 'DT_ADDRRNGLO': 0x6ffffe00, 'DT_GNU_CONFLICT': 0x6ffffef8, + 'DT_GNU_LIBLIST': 0x6ffffef9, 'DT_SUNW_CONFIG': 0x6ffffefa, + 'DT_SUNW_DEPAUDIT': 0x6ffffefb, 'DT_SUNW_AUDIT': 0x6ffffefc, + 'DT_SUNW_PLTPAD': 0x6ffffefd, 'DT_SUNW_MOVETAB': 0x6ffffefe, + 'DT_SYMINFO': 0x6ffffeff, 'DT_ADDRRNGHI': 0x6ffffeff, # dup + 'DT_VERSYM': 0x6ffffff0, 'DT_GNU_VERSYM': 0x6ffffff0, # dup + 'DT_RELACOUNT': 0x6ffffff9, 'DT_RELCOUNT': 0x6ffffffa, + 'DT_FLAGS_1': 0x6ffffffb, 'DT_VERDEF': 0x6ffffffc, + 'DT_VERDEFNUM': 0x6ffffffd, 'DT_VERNEED': 0x6ffffffe, + 'DT_VERNEEDNUM': 0x6fffffff, + 'DT_IA_64_PLT_RESERVE': 0x70000000, 'DT_SUNW_AUXILIARY': 0x7ffffffd, + 'DT_SUNW_USED': 0x7ffffffe, 'DT_SUNW_FILTER': 0x7fffffff +} + +elf_dyn_fields = [ 'd_tag', 'd_val', 'd_ptr' ] + +elf_ehdr_flags = { # no known flags +} + +elf_ehdr_type = { # e_type + 'ET_NONE': 0, 'ET_REL': 1, 'ET_EXEC': 2, 'ET_DYN': 3, 'ET_CORE': 4 +} + +elf_ehdr_machine = { # e_machine + 'EM_NONE': 0, 'EM_M32': 1, 'EM_SPARC': 2, 'EM_386': 3, 'EM_68K': 4, + 'EM_88K': 5, 'EM_486': 6, 'EM_860': 7, 'EM_MIPS': 8, 'EM_S370': 9, + 'EM_MIPS_RS3_LE': 10, 'EM_MIPS_RS4_BE': 10, 'EM_PARISC': 15, + 'EM_VPP500': 17, 'EM_SPARC32PLUS': 18, 'EM_960': 19, 'EM_PPC': 20, + 'EM_PPC64': 21, 'EM_S390': 22, 'EM_V800': 36, 'EM_FR20': 37, + 'EM_RH32': 38, 'EM_RCE': 39, 'EM_ARM': 40, 'EM_ALPHA_STD': 41, + 'EM_SH': 42, 'EM_SPARCV9': 43, 'EM_TRICORE': 44, 'EM_ARC': 45, + 'EM_H8_300': 46, 'EM_H8_300H': 47, 'EM_H8S': 48, 'EM_H8_500': 49, + 'EM_IA_64': 50, 'EM_MIPS_X': 51, 'EM_COLDFIRE': 52, + 'EM_68HC12': 53, 'EM_MMA': 54, 'EM_PCP': 55, 'EM_NCPU': 56, + 'EM_NDR1': 57, 'EM_STARCORE': 58, 'EM_ME16': 59, 'EM_ST100': 60, + 'EM_TINYJ': 61, 'EM_X86_64': 62, 'EM_ALPHA': 0x9026 +} + +elf_ei_version = { # e_version + 'EV_NONE': 0, 'EV_CURRENT': 1 +} + +elf_ei_class = { + 'ELFCLASSNONE': 0, 'ELFCLASS32': 1, 'ELFCLASS64': 2 +} + +elf_ei_data = { + 'ELFDATANONE': 0, 'ELFDATA2LSB': 1, 'ELFDATA2MSB': 2 +} + +elf_ei_osabi = { + # Official values. + 'ELFOSABI_NONE': 0, + 'ELFOSABI_HPUX': 1, + 'ELFOSABI_NETBSD': 2, + 'ELFOSABI_GNU': 3, + 'ELFOSABI_HURD': 4, + 'ELFOSABI_86OPEN': 5, + 'ELFOSABI_SOLARIS': 6, + 'ELFOSABI_AIX': 7, + 'ELFOSABI_IRIX': 8, + 'ELFOSABI_FREEBSD': 9, + 'ELFOSABI_TRU64': 10, + 'ELFOSABI_MODESTO': 11, + 'ELFOSABI_OPENBSD': 12, + 'ELFOSABI_OPENVMS': 13, + 'ELFOSABI_NSK': 14, + 'ELFOSABI_ARM': 97, + 'ELFOSABI_STANDALONE': 255, + # Aliases. + 'ELFOSABI_SYSV': 0, + 'ELFOSABI_LINUX': 3, + 'ELFOSABI_MONTEREY': 7 +} + +elf_ph_fields = [ 'p_align', 'p_filesz', 'p_flags', 'p_memsz', 'p_offset', + 'p_paddr', 'p_type', 'p_vaddr' ] + +elf_ph_flags = { + 'PF_X': 0x1, 'PF_W': 0x2, 'PF_R': 0x4 +} + +elf_ph_type = { + 'PT_NULL': 0, 'PT_LOAD': 1, 'PT_DYNAMIC': 2, 'PT_INTERP': 3, + 'PT_NOTE': 4, 'PT_SHLIB': 5, 'PT_PHDR': 6, 'PT_TLS': 7, + 'PT_LOOS': 0x60000000, 'PT_HIOS': 0x6FFFFFFF, + 'PT_SUNW_UNWIND': 0x6464E550, 'PT_GNU_EHFRAME': 0x6464E550, # dup + 'PT_SUNWBSS': 0x6FFFFFFA, 'PT_SUNWSTACK': 0x6FFFFFFB, + 'PT_SUNWDTRACE': 0x6FFFFFFC, 'PT_SUNWCAP': 0x6FFFFFFD, + 'PT_LOPROC': 0x70000000, 'PT_HIPROC': 0x7FFFFFFF +} + +elf_sh_type = { + 'SHT_NULL': 0, 'SHT_PROGBITS': 1, 'SHT_SYMTAB': 2, 'SHT_STRTAB': 3, + 'SHT_RELA': 4, 'SHT_HASH': 5, 'SHT_DYNAMIC': 6, 'SHT_NOTE': 7, + 'SHT_NOBITS': 8, 'SHT_REL': 9, 'SHT_SHLIB': 10, 'SHT_DYNSYM': 11, + 'SHT_INIT_ARRAY': 14, 'SHT_FINI_ARRAY': 15, 'SHT_PREINIT_ARRAY': 16, + 'SHT_GROUP': 17, 'SHT_SYMTAB_SHNDX': 18, 'SHT_LOOS': 0x60000000, + 'SHT_HIOS': 0x6fffffff, 'SHT_LOPROC': 0x70000000, + 'SHT_HIPROC': 0x7fffffff, 'SHT_LOUSER': 0x80000000, + 'SHT_HIUSER': 0xffffffff, + # OS specific types + 'SHT_SUNW_dof': 0x6FFFFFF4, 'SHT_SUNW_cap': 0x6FFFFFF5, + 'SHT_SUNW_SIGNATURE': 0x6FFFFFF6, + 'SHT_SUNW_ANNOTATE': 0x6FFFFFF7, 'SHT_GNU_LIBLIST': 0x6ffffff7, # dup + 'SHT_SUNW_DEBUGSTR': 0x6FFFFFF8, 'SHT_SUNW_DEBUG': 0x6FFFFFF9, + 'SHT_SUNW_move': 0x6FFFFFFA, 'SHT_SUNW_COMDAT': 0x6FFFFFFB, + 'SHT_SUNW_syminfo': 0x6FFFFFFC, + 'SHT_GNU_verdef': 0x6ffffffd, 'SHT_SUNW_verdef': 0x6ffffffd, # dup + 'SHT_GNU_verneed': 0x6ffffffe, 'SHT_SUNW_verneed': 0x6ffffffe, # dup + 'SHT_GNU_versym': 0x6fffffff, 'SHT_SUNW_versym': 0x6fffffff, # dup + # Processor specific types + 'SHT_IA_64_EXT': 0x70000000, 'SHT_IA_64_UNWIND': 0x70000001 +} + +elf_sh_flags = { + 'SHF_WRITE': 0x1, 'SHF_ALLOC': 0x2, 'SHF_EXECINSTR': 0x4, + 'SHF_MERGE': 0x10, 'SHF_STRINGS': 0x20, 'SHF_INFO_LINK': 0x40, + 'SHF_LINK_ORDER': 0x80, 'SHF_OS_NONCONFORMING': 0x100, + 'SHF_GROUP': 0x200, 'SHF_TLS': 0x400, 'SHF_MASKOS': 0x0ff00000, + 'SHF_MASKPROC': 0xf0000000 +} + +elf_st_bindings = { + 'STB_LOCAL': 0, 'STB_GLOBAL': 1, 'STB_WEAK': 2 +} + +elf_st_flags = { + 'SHF_WRITE': 1, 'SHF_ALLOC': 2, 'SHF_EXECINSTR': 4 +} + +elf_st_types = { + 'STT_NOTYPE': 0, 'STT_OBJECT': 1, 'STT_FUNC': 2, 'STT_SECTION': 3, + 'STT_FILE': 3 +} + +elf_syminfo_flags = { + 'SYMINFO_FLG_DIRECT': 1, + 'SYMINFO_FLG_PASSTHRU': 2, 'SYMINFO_FLG_FILTER': 2, # dup + 'SYMINFO_FLG_COPY': 4, 'SYMINFO_FLG_LAZYLOAD': 8, + 'SYMINFO_FLG_DIRECTBIND': 0x10, 'SYMINFO_FLG_NOEXTDIRECT': 0x20, + 'SYMINFO_FLG_AUXILIARY': 0x40 +} + +elf_syminfo_boundto_types = { + 'SYMINFO_BT_SELF': 0xFFFF, 'SYMINFO_BT_PARENT': 0xFFFE, + 'SYMINFO_BT_NONE': 0xFFFD, 'SYMINFO_BT_EXTERN': 0xFFFC +} + +# Defaults + +defaults = { + # ElfDyn structures + 'd_tag': 'DT_NULL', + 'd_un': '0', + + # fields in an ELf Executable Header + 'e_ehsize': None, + 'e_entry': '0', + 'e_flags': [ '0' ], + 'e_ident': None, + 'e_machine': 'EM_NONE', + 'e_phentsize': None, + 'e_phnum': None, + 'e_phoff': None, + 'e_shentsize': None, + 'e_shnum': None, + 'e_shoff': None, + 'e_shstrndx': None, + 'e_type': 'ET_NONE', + 'e_version': 'EV_CURRENT', + # e_ident bytes + 'ei_class': 'ELFCLASS32', + 'ei_data': 'ELFDATA2LSB', + 'ei_version': 'EV_CURRENT', + 'ei_osabi': 'ELFOSABI_NONE', + 'ei_abiversion': '0', + # File-wide defaults + 'elf_fillchar': '0', + # Elf Notes + 'n_namesz': None, + 'n_descsz': None, + 'n_type': '0', + 'n_data': [ "", "" ], + # Phdr + 'p_align': '1', + 'p_filesz': '0', + 'p_memsz': '0', + 'p_flags': [ '0' ], + 'p_offset': '0', + 'p_paddr': '0', + 'p_type': 'PT_NULL', + 'p_vaddr': '0', + # Shdr + 'sh_addr': '0', + 'sh_addralign': None, + 'sh_data': [], + 'sh_entsize': '0', + 'sh_flags': [ '0' ], + 'sh_info': '0', + 'sh_index': None, + 'sh_link': '0', + 'sh_name': '0', + 'sh_offset': None, + 'sh_size': None, + 'sh_type': 'SHT_NULL', + # Verdaux + 'vda_name': 0, + 'vda_next': 0, + # Verdef + 'vd_version': 1, + 'vd_flags': 0, + 'vd_ndx': 0, + 'vd_cnt': 0, + 'vd_hash': 0, + 'vd_aux': 0, + 'vd_next': 0, + # Vernaux + 'vna_hash': 0, + 'vna_flags': 0, + 'vna_other': 0, + 'vna_name': 0, + 'vna_next': 0, + # Verneed + 'vn_version': 1, + 'vn_cnt': 0, + 'vn_file': 0, + 'vn_aux': 0, + 'vn_next': 0 +} + +# +# Module wide constants. +# + +ELFCLASS32 = elf_ei_class['ELFCLASS32'] +ELFDATA2LSB = elf_ei_data['ELFDATA2LSB'] +SHT_NOBITS = elf_sh_type['SHT_NOBITS'] +SHT_NULL = elf_sh_type['SHT_NULL'] +SHT_STRTAB = elf_sh_type['SHT_STRTAB'] +SHN_LORESERVE= 0xFF00 +SHN_XINDEX = 0xFFFF +# +# Helper functions. +# + +def get(d, key, default): + """Retrieve the value of 'key' from YAML dictionary 'd'. + + The return value is guaranteed to be not 'None'. + """ + v = d.get(key, default) + if v is None: + v = default + return v + +def encode(d, key, default, mapping): + """Return the numeric value of d[key] in map 'mapping'.""" + + v = get(d, key, default) + try: + return mapping[v] + except KeyError: + return int(v) + +def encode_flags(flags, m): + """Convert 'flags' to a single numeric value using mapping 'm'.""" + try: + v = long(flags) + return v + except: + pass + v = 0L + for f in flags: + try: + t = long(m[f]) + except KeyError: + t = long(f) + v |= t + return v + +def check_dict(d, l, node=None): + """Check a dictionary for unknown keys.""" + unknown = [] + for k in d.keys(): + if k not in l: + unknown.append(k) + if len(unknown) > 0: + raise ElfError(node, "{%s} Unknown key(s) %s" % \ + (node.tag, unknown)) + +# +# Helper classes. +# + +class ElfStrTab: + """A ELF string table. + + This class manages strings in an ELF string table section. + """ + + def __init__(self, strs=None): + """Initialize a string table from a list of strings.""" + self.offset = 1 # reserve space for initial null byte + self.htab = {} + if type(strs) == types.StringType: # one string + self.add(strs) + elif type(strs) == types.ListType: # list of strings + for s in strs: + self.add(s) + + def add(self, str): + """Add a string to the string table. + + Returns the offset of the string in the ELF section.""" + try: + return self.lookup(str) + except KeyError: + self.htab[str] = offset = self.offset + self.offset += len(str) + 1 # Keep space for a NUL. + return offset + + def bits(self): + """Return the contents of an ELF string table.""" + + l = self.htab.items() + l.sort(lambda x, y: cmp(x[1],y[1])) # Order by string offset. + ls = [""] # initial NUL + for (ss,oo) in l: + ls.append(ss) + return "\000".join(ls) + "\000" # Add trailing NULs + + def lookup(self, str): + """Return the ELF string table offset for string 'str'.""" + + return self.htab[str] + + +class ElfType: + """A base type for ELF type descriptors. + + Derived classes are expected to provide the following attributes: + + 'fields' -- a list of 4-typles (name, fn, lsz, msz). + + 'name' is the name of a field in the ELF structure. + + 'fn' is a convertor function, one of the functions + 'do_(long,encode,flags)' below. + + 'msz' and 'lsz' provide the appropriate sizes when + generating a binary representation of the type. + """ + + fields = None + def __init__(self, d, node): + """Initialize an ELF datatype from a YAML description. + + Arguments: + d -- a dictionary containing name/value pairs specified + in the text description. + node -- YAML parser node for this element. + """ + + keys = map(lambda t: t[0], self.fields) + check_dict(d, keys, node) + for f in self.fields: + name = f[0] + fn = f[1] + try: + v = fn(d, name) + setattr(self,f[0],v) + except: + raise ElfError(node, + 'key: "%s" value: "%s" unrecognized.' % \ + (name, d[name])) + self._n = node # Save YAML node and associated value + self._d = d # for error reporting. + + def __getitem__(self, attrib): + """Allow an ELF type to be treated like a dictionary.""" + + return getattr(self, attrib) + + def bits(self, formatchar, elfclass): + """Convert an ELF type to its file representation.""" + + format, args = self.getfields(elfclass) + return struct.pack(formatchar + format, *args) + + def formatstring(self, elfclass): + """Return the format string for this type.""" + + if elfclass == ELFCLASS32: + n = 2 + else: + n = 3 + return "".join(map (lambda t: t[n], self.fields)) + + def content(self, elfclass): + """Return a tuple containing the values for an ELF type.""" + + a = [] + if elfclass == ELFCLASS32: + n = 2 + else: + n = 3 + for t in self.fields: + if t[n] != "": + a.append(getattr(self, t[0])) + return tuple(a) + + def getfields(self, elfclass): + """Describe the binary layout of the type. + + Return a tuple (formatstring, *args) describing the + desired binary layout in the manner of the 'struct' + python library module. + """ + + return (self.formatstring(elfclass), + self.content(elfclass)) + + def layout(self, offset, elf): + """Perform any layout-time translation for an ELF type.""" + + return offset + + def size(self, elfclass): + """Return the size of the type in bytes. + + The size returned is independent of the alignment needs of + the type. + """ + + format = self.formatstring(elfclass) + sz = 0 + for f in format: + if f == "B": + sz += 1 + elif f == "H": + sz += 2 + elif f == "I": + sz += 4 + elif f == "Q": + sz += 8 + elif f == "": + pass + else: + raise TypeError, "Invalid format char '%s'." % f + return sz + + +# +# Translation helper functions. +# + +def do_string(d, n): + """Convert a YAML value to a Python string.""" + + v = get(d, n, defaults[n]) + if v: + return str(v) + return v + +def do_long(d, n): + """Convert a YAML value to a Python 'long'.""" + + v = get(d, n, defaults[n]) + if v: + return long(v) + return v + +def do_copy(d, n): + """Copy a YAML value without conversion.""" + + v = get(d, n, defaults[n]) + return v + +def do_encode(xlate): + """Translate a YAML value according to mapping 'xlate'.""" + + return lambda d, n, xl=xlate: encode(d, n, defaults[n], xl) + +def do_flags(xlate): + """Translate a list of flags according to mapping 'xlate'.""" + + return lambda d, n, xl=xlate: encode_flags(get(d, n, defaults[n]), xl) + +# +# Definitions of ELF types. +# + +class ElfCap(ElfType): + """A representation of an ELF Cap structure. + + YAML tag: !Cap + """ + + fields = [ + ('c_tag', do_encode(elf_cap_tag), "I", "Q"), + ('c_un', do_long, "I", "Q") + ] + def __init__(self, cap, node): + ElfType.__init__(self, cap, node) + + +class ElfDyn(ElfType): + """A representation of an ELF Dyn structure. + + YAML tag: !Dyn + """ + + fields = [ + ('d_tag', do_encode(elf_d_tag), "I", "Q"), + ('d_un', do_long, "I", "Q") + ] + + def __init__(self, d, node): + ElfType.__init__(self, d, node) + + +class ElfEhdrIdent(ElfType): + """A representation for the 'ident' field of an ELF Ehdr. + + YAML tag: !Ident + """ + + fields = [ + ('ei_class', do_encode(elf_ei_class), "B", "B"), + ('ei_data', do_encode(elf_ei_data), "B", "B"), + ('ei_version', do_encode(elf_ei_version), "B", "B"), + ('ei_osabi', do_encode(elf_ei_osabi), "B", "B"), + ('ei_abiversion', do_long, "B", "B") + ] + + def __init__(self, ei, node): + ElfType.__init__(self, ei, node) + + def bits(self, format, elfclass): + f, args = self.getfields(elfclass) + s = "\x7FELF" + s += struct.pack(f + 'xxxxxxx', *args) + return s + + +class ElfEhdr(ElfType): + """A representation of an ELF Executable Header. + + YAML tag: !Ehdr + """ + + fields = [ + ('e_ident', do_copy, "", ""), + ('e_type', do_encode(elf_ehdr_type), "H", "H"), + ('e_machine', do_encode(elf_ehdr_machine), "H", "H"), + ('e_version', do_encode(elf_ei_version), "I", "I"), + ('e_entry', do_long, "I", "Q"), + ('e_phoff', do_long, "I", "Q"), + ('e_shoff', do_long, "I", "Q"), + ('e_flags', do_flags(elf_ehdr_flags), "I", "I"), + ('e_ehsize', do_long, "H", "H"), + ('e_phentsize', do_long, "H", "H"), + ('e_phnum', do_long, "H", "H"), + ('e_shentsize', do_long, "H", "H"), + ('e_shnum', do_long, "H", "H"), + ('e_shstrndx', do_copy, "H", "H") + ] + + def __init__(self, eh, node): + """Initialize an Ehdr structure. + + If an 'ident' structure was not specified as part of + the YAML description, initialize it explicitly. + """ + + ElfType.__init__(self, eh, node) + if self.e_ident is None: + self.e_ident = ElfEhdrIdent({}, node) + + def layout(self, offset, elf): + """Layout an ELF Ehdr. + + This method will fill in defaults and/or compute + values for fields that were not specified in the YAML + description. + """ + + elfclass = elf.elfclass() + if elfclass == ELFCLASS32: + e_ehsize = 52 + e_phentsize = 32 + e_shentsize = 40 + alignment = 4 + else: # 64 bit sizes + e_ehsize = 64 + e_phentsize = 56 + e_shentsize = 64 + alignment = 8 + + if self.e_ehsize is None: + self.e_ehsize = e_ehsize + + # Compute e_phnum if needed. + if self.e_phnum is None: + self.e_phnum = len(elf.elf_phdrtab) + + # Compute a value for the e_phentsize field. + if self.e_phentsize is None: + if self.e_phnum: + self.e_phentsize = e_phentsize + else: + self.e_phentsize = 0 + + # Set the e_shentsize field. + if self.e_shentsize is None: + self.e_shentsize = e_shentsize + + # The program header defaults to just after the ELF header. + if self.e_phoff is None: + if self.e_phnum > 0: + self.e_phoff = \ + (self.e_ehsize + (alignment - 1)) & \ + ~(alignment - 1) + else: + self.e_phoff = 0 + + # compute e_shnum + self.nsections = elf.elf_sections.get_shnum() + if self.nsections > 0: + if self.e_shstrndx is None: + self.e_shstrndx = '.shstrtab' + if type(self.e_shstrndx) == types.StringType: + self.e_shstrndx = \ + elf.elf_sections.get_index(self.e_shstrndx) + elif type(self.e_shstrndx) == types.IntType or \ + type(self.e_shstrndx) == types.LongType: + pass + else: + raise ElfError(self._n, "Unparseable e_shstrndx field.") + if self.e_shstrndx is None: + raise ElfError(self._n, + 'Cannot determine section ' + \ + 'name string table index.') + else: + if self.e_shstrndx is None: + self.e_shstrndx = 0 + + if self.e_shnum is None: + self.e_shnum = self.nsections + + # section data comes after the program header by default. The + # section header table is placed after all section data. + + if self.e_phnum > 0: + offset = self.e_phoff + self.e_phnum * self.e_phentsize + else: + offset = self.e_ehsize + offset = elf.elf_sections.layout(offset, elf) + if self.e_shoff is None: + if self.nsections > 0: + self.e_shoff = (offset + (alignment-1)) & \ + ~(alignment-1) + else: + self.e_shoff = 0 + + if self.nsections >= SHN_LORESERVE: + elf.elf_sections.set_extended_shnum(self.nsections) + self.e_shnum = 0 + if self.e_shstrndx >= SHN_XINDEX: + elf.elf_sections.set_extended_shstrndx(self.e_shstrndx) + self.e_shstrndx = SHN_XINDEX + + def bits(self, formatchar, elfclass): + """Return the file representation of an Elf Ehdr.""" + + s = self.e_ident.bits(formatchar, elfclass) + s += ElfType.bits(self, formatchar, elfclass) + + return s + + +class ElfLong: + """Wrapper around a python Int/Long.""" + + def __init__(self, v): + self._v = long(v) + + def bits(self, formatchar, elfclass): + """Return the file representation for this object. + + Depending on the number of bits needed to represent + the number, the returned bits would be either 4 or + 8 bytes wide. + """ + + if self._v > 0xFFFFFFFFL: + f = formatchar + "Q" + else: + f = formatchar + "I" + return struct.pack(f, self._v) + + +class ElfMove(ElfType): + """A representation of an Elf Move type. + + YAML tag: !Move + """ + + fields = [ + ('m_value', do_long, "I", "I"), + ('m_info', do_long, "I", "Q"), + ('m_poffset', do_long, "I", "Q"), + ('m_repeat', do_long, "H", "H"), + ('m_stride', do_long, "H", "H") + ] + + def __init__(self, move, node): + ElfType.__init__(self, move, node) + + +class ElfNote(ElfType): + """A representation of an Elf Note type. + + YAML tag: !Note + + The data in the note is held in YAML node named 'n_data' which is + a pair of strings, one for the note's name field and one for the + description. + + If the fields 'n_namesz' and 'n_descz' aren't specified, they + are computed from the contents of 'n_data'. + """ + + fields = [ + ('n_namesz', do_long, "I", "I"), + ('n_descsz', do_long, "I", "I"), + ('n_type', do_long, "I", "I"), + ('n_data', do_copy, "", "") + ] + + def __init__(self, note, node): + ElfType.__init__(self, note, node) + self._note = note + + def layout(self, offset, elfclass): + if len(self.n_data) != 2: + raise ElfError(node, "Note data not a pair of strings.") + + for nd in self.n_data: + if isinstance(nd, ElfType): + nd.layout(offset, elfclass) + + if self.n_namesz is None: + self.n_namesz = len(self.n_data[0]) + if self.n_descsz is None: + self.n_descsz = len(self.n_data[1]) + + def bits(self, format, elfclass): + b = ElfType.bits(self, format, elfclass) + nbits = str(self.n_data[0]) + dbits = str(self.n_data[1]) + return b + nbits + dbits + + +class ElfPhdr(ElfType): + """A representation of an ELF Program Header Table entry. + + YAML tag: !Phdr + """ + + fields = [ # NOTE: class-dependent field ordering + ('p_align', do_long), + ('p_filesz', do_long), + ('p_flags' , do_flags(elf_ph_flags), ), + ('p_memsz' , do_long), + ('p_offset', do_long), + ('p_paddr' , do_long), + ('p_type' , do_encode(elf_ph_type)), + ('p_vaddr' , do_long) + ] + + def __init__(self, ph, node): + ElfType.__init__(self, ph, node) + + def to_string(self): + """Helper during debugging.""" + + s = "Phdr(type:%(p_type)d,flags:%(p_flags)d," \ + "offset:%(p_offset)ld,vaddr:%(p_vaddr)ld," \ + "paddr:%(p_paddr)ld,filesz:%(p_filesz)ld," \ + "memsz:%(p_memsz)ld)" % self + return s + + def bits(self, formatchar, elfclass): + """Return the file representation of a Phdr.""" + + f = formatchar + # Phdr structures are laid out in a class-dependent way + if elfclass == ELFCLASS32: + f += "IIIIIIII" + s = struct.pack(f, + self.p_type, + self.p_offset, + self.p_vaddr, + self.p_paddr, + self.p_filesz, + self.p_memsz, + self.p_flags, + self.p_align) + else: + f += "IIQQQQQQ" + s = struct.pack(f, + self.p_type, + self.p_flags, + self.p_offset, + self.p_vaddr, + self.p_paddr, + self.p_filesz, + self.p_memsz, + self.p_align) + return s + +class ElfRel(ElfType): + """A representation of an ELF Rel type. + + YAML tag: !Rel + """ + + fields = [ + ('r_offset', do_long, "I", "Q"), + ('r_info', do_long, "I", "Q") + ] + + def __init__(self, rel, node): + ElfType.__init__(self, rel, node) + + +class ElfRela(ElfType): + """A representation of an ELF Rela type. + + YAML tag: !Rela + """ + + fields = [ + ('r_offset', do_long, "I", "Q"), + ('r_info', do_long, "I", "Q"), + ('r_addend', do_long, "I", "Q") + ] + + def __init__(self, rela, node): + ElfType.__init__(self, rela, node) + + +class ElfSection(ElfType): + """A representation of an ELF Section. + + YAML tag: !Section + + A section description consists of the fields that make up an ELF + section header entry and an additional field 'sh_data' that + contains the data associated with this section. + + 'sh_data' may be a YAML string, or a YAML list of items that + comprise the content of the section. + """ + + fields = [ + ('sh_name', do_string, "I", "I"), + ('sh_type', do_encode(elf_sh_type), "I", "I"), + ('sh_flags', do_flags(elf_sh_flags), "I", "Q"), + ('sh_addr', do_long, "I", "Q"), + ('sh_offset', do_long, "I", "Q"), + ('sh_size', do_long, "I", "Q"), + ('sh_link', do_long, "I", "I"), + ('sh_info', do_long, "I", "I"), + ('sh_addralign', do_copy, "I", "Q"), + ('sh_entsize', do_long, "I", "Q"), + ('sh_data', do_copy, "", ""), + ('sh_index', do_long, "", "") + ] + + def __init__(self, shdr, node): + """Initialize a section descriptor.""" + + ElfType.__init__(self, shdr, node) + if type(self.sh_data) != types.ListType: + self.sh_data = list(self.sh_data) + if self.sh_addralign is None: + if self.sh_type == SHT_NULL or self.sh_type == SHT_NOBITS: + self.sh_addralign = 0 + else: + self.sh_addralign = 1 + else: + if (self.sh_addralign == 0 or \ + (self.sh_addralign & (self.sh_addralign - 1)) != 0): + raise ElfError(node, + "'sh_addralign' not a power of two.") + self._data = None # 'cache' of translated data + self._strtab = None + + def to_string(self): + """Helper function during debugging.""" + + return "Section(name:%(sh_name)s,type:%(sh_type)d," \ + "flags:%(sh_flags)x,addr:%(sh_addr)d,"\ + "offset:%(sh_offset)d,size:%(sh_size)d," \ + "link:%(sh_link)d,info:%(sh_info)d," \ + "addralign:%(sh_addralign)d,entsize:%(sh_entsize)d)" % \ + self + + def make_strtab(self): + """Create a string table from section contents.""" + + self._strtab = ElfStrTab(self.sh_data) + + def string_to_index(self, name): + """Convert 'name' to an offset inside a string table. + + Only valid for sections of type SHT_STRTAB.""" + + if self._strtab: + return self._strtab.lookup(name) + raise ElfError(None, 'Cannot translate "%s" to an index.' % name) + + def bits(self, formatchar, elfclass): + raise AssertionError, "Section objects should use " \ + "databits() or headerbits()" + + def layout(self, offset, elf): + """Prepare an ELF section for output.""" + + if type(self.sh_name) == types.StringType: + # first try convert it to a long + try: + self.sh_name = long(self.sh_name) + except ValueError: # lookup in string table + try: + self.sh_name = \ + elf.section_name_index(self.sh_name) + except KeyError: + raise ElfError(self._n, + "Section name '%s' not in string table." % \ + self.sh_name) + # give a chance for the contents of a section to xlate strings + for d in self.sh_data: + if isinstance(d, ElfType): + d.layout(offset, elf) + # compute the space used by the section data + self._data = self.databits(elf.formatchar(), elf.elfclass()) + + align = self.sh_addralign + if align == 0: + align = 1 + if self.sh_type == SHT_NULL or self.sh_type == SHT_NOBITS: + isnulltype = 1 + else: + isnulltype = 0 + + offset = (offset + (align - 1)) & ~(align - 1) + if self.sh_size is None: + if isnulltype: + self.sh_size = 0 + else: + self.sh_size = len(self._data) + if self.sh_offset is None: + if isnulltype: + self.sh_offset = 0 + else: + self.sh_offset = offset + if isnulltype: # ignore bits for null types + return offset + return offset + len(self._data) + + def databits(self, formatchar, elfclass): + """Return the contents of a section.""" + + if self._data: + return self._data + # special-case string table handling + if self.sh_type == SHT_STRTAB: + return self._strtab.bits() + # 'normal' section + s = "" + for d in self.sh_data: + if isinstance(d, ElfType): + s += d.bits(formatchar, elfclass) + elif isinstance(d, types.LongType): + s += struct.pack(formatchar + "Q", d) + elif isinstance(d, types.IntType): + s += struct.pack(formatchar + "I", d) + else: + s += str(d) + return s + + def headerbits(self, formatchar, elfclass): + """Return the file representation of the section header.""" + + return ElfType.bits(self, formatchar, elfclass) + + +class ElfSym(ElfType): + """A representation for an ELF Symbol type. + + YAML tag: !Sym + """ + + fields = [ # NOTE: class-dependent layout. + ('st_info', do_long, "B", "B"), + ('st_name', do_string, "I", "I"), + ('st_other', do_long, "B", "B"), + ('st_shndx', do_string, "H", "H"), + ('st_size', do_long, "I", "Q"), + ('st_value', do_long, "I", "Q") + ] + + def __init__(self, sym, node): + ElfType.__init__(self, sym, node) + + def bits(self, format, elfclass): + """Return the file representation for an ELF Sym.""" + + if elfclass == ELFCLASS32: + s = struct.pack(format + "IIIBBH", + self.st_name, + self.st_value, + self.st_size, + self.st_info, + self.st_other, + self.st_shndx) + else: + s = struct.pack(format + "IBBHQQ", + self.st_name, + self.st_info, + self.st_other, + self.st_shndx, + self.st_value, + self.st_size) + return s + + def layout(self, offset, elf): + """Perform layout-time conversions for an ELF Sym. + + String valued fields are converted to offsets into + string tables. + """ + + if type(self.st_shndx) == types.StringType: + self.st_shndx = \ + elf.elf_sections.get_index(self.st_shndx) + if self.st_shndx is None: + raise ElfError(self._n, "Untranslateable 'st_shndx' " + \ + "value \"%s\"." % self.st_shndx) + + if type(self.st_name) == types.StringType: + try: + strtab = \ + elf.elf_sections[self.st_shndx]._strtab + except IndexError: + raise ElfError(self._n, "'st_shndx' out of range") + if strtab is None: + raise ElfError(self._n, "'st_shndx' not of type STRTAB.") + + try: + self.st_name = strtab.lookup(self.st_name) + except KeyError: + raise ElfError(self._n, + 'unknown string "%s"' % self.st_name) + return offset + + +class ElfSyminfo(ElfType): + """A representation of an ELF Syminfo type. + + YAML tag: !Syminfo + """ + + fields = [ + ('si_boundto', do_encode(elf_syminfo_boundto_types), "H", "H"), + ('si_flags', do_flags(elf_syminfo_flags), "H", "H") + ] + + def __init__(self, syminfo, node): + ElfType.__init__(self, syminfo, node) + + +class ElfVerdaux(ElfType): + """A representation of an ELF Verdaux type.""" + + fields = [ + ('vda_name', do_long, "I", "I"), + ('vda_next', do_long, "I", "I") + ] + + def __init__(self, verdaux, node): + ElfType.__init__(self, verdaux, node) + + +class ElfVerdef(ElfType): + """A representation of an ELF Verdef type.""" + + fields = [ + ('vd_version', do_long, "H", "H"), + ('vd_flags', do_long, "H", "H"), + ('vd_ndx', do_long, "H", "H"), + ('vd_cnt', do_long, "H", "H"), + ('vd_hash', do_long, "I", "I"), + ('vd_aux', do_long, "I", "I"), + ('vd_next', do_long, "I", "I") + ] + + def __init__(self, verdef, node): + ElfType.__init__(self, verdef, node) + + +class ElfVernaux(ElfType): + """A representation of an ELF Vernaux type.""" + + fields = [ + ('vna_hash', do_long, "I", "I"), + ('vna_flags', do_long, "H", "H"), + ('vna_other', do_long, "H", "H"), + ('vna_name', do_long, "I", "I"), + ('vna_next', do_long, "I", "I") + ] + + def __init__(self, vernaux, node): + ElfType.__init__(self, vernaux, node) + +class ElfVerneed(ElfType): + """A representation of an ELF Verneed type.""" + + fields = [ + ('vn_version', do_long, "H", "H"), + ('vn_cnt', do_long, "H", "H"), + ('vn_file', do_long, "I", "I"), + ('vn_aux', do_long, "I", "I"), + ('vn_next', do_long, "I", "I") + ] + + def __init__(self, verneed, node): + ElfType.__init__(self, verneed, node) + + +# +# Aggregates +# + +class ElfPhdrTable: + """A representation of an ELF Program Header Table. + + A program header table is a list of program header entry sections. + """ + + def __init__(self, phdr): + """Initialize a program header table object. + + Argument 'phdr' is a list of parsed ElfPhdr objects. + """ + + self.pht_data = [] + for ph in phdr: + if type(ph) == types.DictType: + ph = ElfPhdr(ph) + elif not isinstance(ph, ElfPhdr): + raise ElfError(ph.node, + "Program Header Table " + "contains non header data.") + self.pht_data.append(ph) + + def bits(self, formatchar, elfclass): + """Return the file representation of the Phdr table.""" + + s = "" + for d in self.pht_data: + s += d.bits(formatchar, elfclass) + return s + + def __len__(self): + """Return the number of program header table entries.""" + + return len(self.pht_data) + + def __iter__(self): + """Return an iterator for traversing Phdr entries.""" + + return self.pht_data.__iter__() + + +class ElfSectionList: + """A list of ELF sections.""" + + def __init__(self, shlist): + """Initialize an ELF section list. + + Argument 'shlist' is a list of parser ElfSection + objects. + """ + + self.shl_sections = shlist + self.shl_sectionnames = [] + self.shl_nentries = len(shlist) + + for sh in shlist: + if not isinstance(sh, ElfSection): + raise ElfError(None, + """Section 'sections' contains + unrecognized data.""") + if sh.sh_index is not None: + if self.shl_nentries <= sh.sh_index: + self.shl_nentries = sh.sh_index + 1 + self.shl_sectionnames.append((sh.sh_name, sh.sh_index)) + if sh.sh_type == SHT_STRTAB: # a string table + sh.make_strtab() + + def __len__(self): + """Return the number of ELF sections.""" + + return len(self.shl_sections) + + def __iter__(self): + """Iterate through ELF sections.""" + + return self.shl_sections.__iter__() + + def __getitem__(self, ind): + """Retrieve the ELF section at index 'ind'.""" + + try: + return self.shl_sections[ind] + except IndexError: + for sh in self.shl_sections: + if sh.sh_index == ind: + return sh + raise IndexError, "no section at index %d" % ind + + def layout(self, offset, elf): + """Compute the layout for section.""" + + if len(self.shl_sections) == 0: + return 0 + for sh in self.shl_sections: # layout sections + offset = sh.layout(offset, elf) + return offset + + def get_index(self, name): + """Return the section index for section 'name', or 'None'.""" + + c = 0 + for (n,i) in self.shl_sectionnames: + if n == name: + if i is None: + return c + else: + return i + c += 1 + return None + + def get_shnum(self): + """Retrieve the number of sections in this container.""" + + return self.shl_nentries + + def set_extended_shnum(self, shnum): + """Set the extended section number.""" + + sh = self.shl_sections[0] + sh.sh_size = shnum + + def set_extended_shstrndx(self, strndx): + """Set the extended string table index.""" + + sh = self.shl_sections[0] + sh.sh_link = strndx + +class Elf: + """A representation of an ELF object.""" + + def __init__(self, yamldict, ehdr, phdrtab, sections): + self._d = yamldict + self._n = None + self.elf_ehdr = ehdr + self.elf_phdrtab = phdrtab + self.elf_sections = sections + self.elf_fillchar = long(get(yamldict, 'elf_fillchar', + defaults['elf_fillchar'])) + def byteorder(self): + """Return the byteorder for this ELF object.""" + return self.elf_ehdr.e_ident.ei_data + + def elfclass(self): + """Return the ELF class for this ELF object.""" + return self.elf_ehdr.e_ident.ei_class + + def formatchar(self): + """Return the format character corresponding to the ELF + byteorder.""" + + if self.byteorder() == ELFCLASS32: + return "<" + else: + return ">" + + def layout(self): + """Compute a file layout for this ELF object and update + internal data structures.""" + + self.elf_ehdr.layout(0, self) + + + def section_name_index(self, name): + """Compute index of section 'name' in the section name string table.""" + + strndx = self.elf_ehdr.e_shstrndx + if strndx is None: + return None + return self.elf_sections[strndx].string_to_index(name) + + def write(self, fn): + """Write out the file representation of an ELF object. + + Argument 'fn' denotes the destination.""" + + of = file(fn, 'w') + + formatchar = self.formatchar() + elfclass = self.elfclass() + + # Write out the header + of.write(self.elf_ehdr.bits(formatchar, elfclass)) + + # Write out the program header table if present + if self.elf_phdrtab: + self.reposition(of, self.elf_ehdr.e_phoff) + for ph in self.elf_phdrtab: + of.write(ph.bits(formatchar, elfclass)) + # Write out the sections + if self.elf_sections: + # First the contents of the sections + for sh in self.elf_sections: + if sh.sh_type == SHT_NULL or sh.sh_type == SHT_NOBITS: + continue + self.reposition(of, sh.sh_offset) + of.write(sh.databits(formatchar, elfclass)) + # Then the header table + self.reposition(of, self.elf_ehdr.e_shoff) + for sh in self.elf_sections: + if sh.sh_index: + new_offset = sh.sh_index * self.elf_ehdr.e_shentsize + \ + self.elf_ehdr.e_shoff + self.reposition(of, new_offset) + of.write(sh.headerbits(formatchar, elfclass)) + of.close() + + def reposition(self, f, offset): + """Reposition file `f' to offset `offset', filling gaps with + the configured fill character as needed.""" + + pos = f.tell() + if offset == pos: + return + if offset < pos or (offset > pos and self.elf_fillchar == 0): + f.seek(offset, 0) + return + s = ("%c" % self.elf_fillchar) * (offset - pos) + f.write(s) + + +# +# YAML Parser configuration and helpers. +# + +yaml_tags = [ + (u'!Cap', ElfCap), + (u'!Dyn', ElfDyn), + (u'!Ehdr', ElfEhdr), + (u'!Ident', ElfEhdrIdent), + (u'!Move', ElfMove), + (u'!Note', ElfNote), + (u'!Phdr', ElfPhdr), + (u'!Rel', ElfRel), + (u'!Rela', ElfRela), + (u'!Section', ElfSection), + (u'!Sym', ElfSym), + (u'!Syminfo', ElfSyminfo), + (u'!Verdaux', ElfVerdaux), + (u'!Verdef', ElfVerdef), + (u'!Vernaux', ElfVernaux), + (u'!Verneed', ElfVerneed) ] + +def init_parser(): + for t in yaml_tags: + yaml.add_constructor(t[0], # lamdba: loader, node, class + lambda l, n, c=t[1]: \ + c(l.construct_mapping(n, deep=True), n)) + +def make_elf(yd): + """Convert a YAML description `yd' of an ELF file into an + ELF object.""" + + try: + eh = yd['ehdr'] + except KeyError: + eh = ElfEhdr({}, None) + + phdrtab = ElfPhdrTable(get(yd, 'phdrtab', {})) + sectionlist = ElfSectionList(get(yd, 'sections', {})) + + return Elf(yd, eh, phdrtab, sectionlist) + + +# +# MAIN +# + +if __name__ == '__main__': + parser = optparse.OptionParser(usage=usage, version=version, + description=description) + parser.add_option("-o", "--output", dest="output", + help="write output to FILE [default: %default]", + metavar="FILE", default="a.out") + parser.add_option("-N", "--no-shstrtab", dest="do_shstrtab", + help="do not create a string table section for " + "section names if missing", action="store_false", + metavar="BOOLEAN", default=True) + parser.add_option("-U", "--no-shnundef", dest="do_shnundef", + help="do not create a section header for index " + "SHN_UNDEF if missing", action="store_false", + metavar="BOOLEAN", default=True) + + (options, args) = parser.parse_args() + + if len(args) > 1: + parser.error("only one input-file must be specified") + + try: + if args: + stream = file(args[0], 'r') + else: + stream = sys.stdin + except IOError, x: + parser.error("cannot open stream: %s" % x) + + init_parser() + + try: + elf = make_elf(yaml.load(stream)) + elf.layout() + elf.write(options.output) + except yaml.YAMLError, x: + parser.error("cannot parse stream: %s" % x) + except ElfError, msg: + print msg + sys.exit(1) + + + +# Local Variables: +# mode: python +# tab-width: 4 +# py-indent-offset: 4 +# End: |