1#!/usr/bin/env python 2# 3# This script converts a textual (YAML) description of an ELF file to 4# an equivalent 'binary' file. 5# 6# The YAML description may have the following top-level keys: 7# 8# 'elf_fillchar': char 9# Sets the fill character to 'char'. 10# 'ehdr': EHDR-DESCRIPTOR 11# Defines an ELF Ehdr structure. 12# 'phdrtab': list-of(PHDR-DESCRIPTOR) 13# Defines the contents of the ELF Program Header table. 14# Each `Phdr' descriptor represents one ELF Phdr entry. 15# 'sections': list-of(SECTION-DESCRIPTOR) 16# Defines the content of each section in the file. Each 17# `SECTION-DESCRIPTOR' contains information for the 18# section `header' and the actual data for the section. 19# 20# The script will compute reasonable defaults for any fields 21# left unspecified in the YAML description. 22# 23# Descriptors EHDR-DESCRIPTOR and PHDR-DESCRIPTOR may be specified 24# as a YAML key-value set. The key names correspond to the 25# field names of the corresponding ELF structures, e.g., 'e_machine' 26# and 'e_ident' for the Ehdr and 'p_type' and 'p_paddr' for 27# a Phdr entry. 28# 29# Descriptor SECTION-DESCRIPTOR contains the fields in an ELF 30# Shdr structure and an additional member 'sh_data', whose 31# value is the data for the section. 32# 33# Example: 34# 35# <snip> 36# ehdr: !Ehdr 37# e_ident: !Ident 38# ei_class: ELFCLASS32 39# ei_data: ELFDATA2MSB 40# e_machine: EM_PPC 41# phdrtab: 42# - !Phdr 43# ph_type: PHT_NULL 44# ... other program header fields ... 45# - !Phdr 46# ... etc. ... 47# sections: 48# - !Section 49# sh_name: .dynsym 50# ... other section header fields ... 51# sh_data: # ... list of data ... 52# - !Dyn 53# d_tag: 0xdeadcode 54# - !Dyn 55# d_tag: 0xcafebabe 56# - !Section 57# sh_name: .shstrtab 58# sh_type: SHT_STRTAB 59# sh_data: 60# - string1 61# - string2 62# </snip> 63# 64# :: Handling of strings :: 65# 66# Fields like 'sh_name' (in a section header) are defined to contain 67# an integer index into a specified string table (in this case a 68# section with name '.shstrtab'). Other ELF data structures use a 69# similar convention; names in a '.dynamic' section as stored as 70# indices into a '.dynstr' section. In the YAML descriptor, such 71# fields may be specified as indices, which are used as-is, or as text 72# strings which are converted to the appropriate string index. 73# For convenience in creating ELF objects with a large number of 74# sections, a section index may be manually specified using a 75# 'sh_index' pseudo field. 76# 77# $Id: elfc 1718 2011-08-12 07:30:43Z jkoshy $ 78 79version = "%prog 1.0" 80usage = "usage: %prog [options] [input-file]" 81description = """Create an ELF binary from a textual description in """ + \ 82 """'input-file' (or stdin)""" 83 84import optparse, re, struct, sys, types, yaml 85 86class ElfError(Exception): 87 """An exception signalled during conversion.""" 88 89 def __init__(self, node=None, msg=None): 90 """Initialize an exception object. 91 92 Arguments: 93 node -- a YAML parse tree node. 94 msg -- human readable message associated with this 95 exception. 96 """ 97 if node: 98 self.ee_start = node.start_mark.line + 1 99 self.ee_end = node.end_mark.line + 1 100 else: 101 self.ee_start = self.ee_end = -1 102 self.ee_msg = msg 103 104 def __str__(self): 105 """Form a printable representation of an exception.""" 106 107 if self.ee_start != -1: 108 if self.ee_start == self.ee_end: 109 return "Error: line %d: %s" % (self.ee_start, 110 self.ee_msg) 111 else: 112 return "Error: lines %d--%d: %s" % \ 113 (self.ee_start, self.ee_end, 114 self.ee_msg) 115 else: 116 return "Error: %s" % self.ee_msg 117 118 119# 120# Mappings used by the 'encode()' function 121# 122 123elf_cap_tag = { 124 'CA_SUNW_NULL': 0, 'CA_SUNW_HW_1': 1, 'CA_SUNW_SF_1': 2 125} 126 127elf_d_flags = { 128 'DF_ORIGIN': 0x0001, 'DF_SYMBOLIC': 0x0002, 'DF_TEXTREL': 0x0004, 129 'DF_BIND_NOW': 0x0006, 'DF_STATIC_TLS': 0x0010 130} 131 132elf_d_tag = { 133 # from <sys/elf_common.h> 134 'DT_NULL': 0, 'DT_NEEDED': 1, 'DT_PLTRELSZ': 2, 'DT_PLTGOT': 3, 135 'DT_HASH': 4, 'DT_STRTAB': 5, 'DT_SYMTAB': 6, 'DT_RELA': 7, 136 'DT_RELASZ': 8, 'DT_RELAENT': 9, 'DT_STRSZ': 10, 'DT_SYMENT': 11, 137 'DT_INIT': 12, 'DT_FINI': 13, 'DT_SONAME': 14, 'DT_RPATH': 15, 138 'DT_SYMBOLIC': 16, 'DT_REL': 17, 'DT_RELSZ': 18, 'DT_RELENT': 19, 139 'DT_PLTREL': 20, 'DT_DEBUG': 21, 'DT_TEXTREL': 22, 'DT_JMPREL': 23, 140 'DT_BIND_NOW': 24, 'DT_INIT_ARRAY': 25,'DT_FINI_ARRAY': 26, 141 'DT_INIT_ARRAYSZ': 27, 'DT_FINI_ARRAYSZ': 28, 'DT_RUNPATH': 29, 142 'DT_FLAGS': 30, 'DT_ENCODING': 32, 'DT_PREINIT_ARRAY': 32, 143 'DT_PREINIT_ARRAYSZ': 33, 'DT_LOOS': 0x6000000d, 'DT_HIOS': 0x6ffff000, 144 'DT_LOPROC': 0x70000000, 'DT_HIPROC': 0x7fffffff, 145 'DT_SUNW_AUXILIARY': 0x6000000D, 'DT_SUNW_RTLDINF': 0x6000000E, 146 'DT_SUNW_FILTER': 0x6000000F, 'DT_SUNW_CAP': 0x60000010, 147 # from "usr.bin/elfdump/elfdump.c" 148 'DT_GNU_PRELINKED': 0x6ffffdf5, 'DT_GNU_CONFLICTSZ': 0x6ffffdf6, 149 'DT_GNU_LIBLISTSZ': 0x6ffffdf7, 'DT_SUNW_CHECKSUM': 0x6ffffdf78, 150 'DT_PLTPADSZ': 0x6ffffdf79, 'DT_MOVEENT': 0x6ffffdfa, 151 'DT_MOVESZ': 0x6ffffdfb, 'DT_FEATURE': 0x6ffffdfc, 152 'DT_FEATURE': 0x6ffffdfd, 'DT_POSFLAG_1': 0x6ffffdfe, 153 'DT_SYMINENT': 0x6ffffdff, 'DT_VALRNGHI': 0x6ffffdff, # dup 154 'DT_ADDRRNGLO': 0x6ffffe00, 'DT_GNU_CONFLICT': 0x6ffffef8, 155 'DT_GNU_LIBLIST': 0x6ffffef9, 'DT_SUNW_CONFIG': 0x6ffffefa, 156 'DT_SUNW_DEPAUDIT': 0x6ffffefb, 'DT_SUNW_AUDIT': 0x6ffffefc, 157 'DT_SUNW_PLTPAD': 0x6ffffefd, 'DT_SUNW_MOVETAB': 0x6ffffefe, 158 'DT_SYMINFO': 0x6ffffeff, 'DT_ADDRRNGHI': 0x6ffffeff, # dup 159 'DT_VERSYM': 0x6ffffff0, 'DT_GNU_VERSYM': 0x6ffffff0, # dup 160 'DT_RELACOUNT': 0x6ffffff9, 'DT_RELCOUNT': 0x6ffffffa, 161 'DT_FLAGS_1': 0x6ffffffb, 'DT_VERDEF': 0x6ffffffc, 162 'DT_VERDEFNUM': 0x6ffffffd, 'DT_VERNEED': 0x6ffffffe, 163 'DT_VERNEEDNUM': 0x6fffffff, 164 'DT_IA_64_PLT_RESERVE': 0x70000000, 'DT_SUNW_AUXILIARY': 0x7ffffffd, 165 'DT_SUNW_USED': 0x7ffffffe, 'DT_SUNW_FILTER': 0x7fffffff 166} 167 168elf_dyn_fields = [ 'd_tag', 'd_val', 'd_ptr' ] 169 170elf_ehdr_flags = { # no known flags 171} 172 173elf_ehdr_type = { # e_type 174 'ET_NONE': 0, 'ET_REL': 1, 'ET_EXEC': 2, 'ET_DYN': 3, 'ET_CORE': 4 175} 176 177elf_ehdr_machine = { # e_machine 178 'EM_NONE': 0, 'EM_M32': 1, 'EM_SPARC': 2, 'EM_386': 3, 'EM_68K': 4, 179 'EM_88K': 5, 'EM_486': 6, 'EM_860': 7, 'EM_MIPS': 8, 'EM_S370': 9, 180 'EM_MIPS_RS3_LE': 10, 'EM_MIPS_RS4_BE': 10, 'EM_PARISC': 15, 181 'EM_VPP500': 17, 'EM_SPARC32PLUS': 18, 'EM_960': 19, 'EM_PPC': 20, 182 'EM_PPC64': 21, 'EM_S390': 22, 'EM_V800': 36, 'EM_FR20': 37, 183 'EM_RH32': 38, 'EM_RCE': 39, 'EM_ARM': 40, 'EM_ALPHA_STD': 41, 184 'EM_SH': 42, 'EM_SPARCV9': 43, 'EM_TRICORE': 44, 'EM_ARC': 45, 185 'EM_H8_300': 46, 'EM_H8_300H': 47, 'EM_H8S': 48, 'EM_H8_500': 49, 186 'EM_IA_64': 50, 'EM_MIPS_X': 51, 'EM_COLDFIRE': 52, 187 'EM_68HC12': 53, 'EM_MMA': 54, 'EM_PCP': 55, 'EM_NCPU': 56, 188 'EM_NDR1': 57, 'EM_STARCORE': 58, 'EM_ME16': 59, 'EM_ST100': 60, 189 'EM_TINYJ': 61, 'EM_X86_64': 62, 'EM_ALPHA': 0x9026 190} 191 192elf_ei_version = { # e_version 193 'EV_NONE': 0, 'EV_CURRENT': 1 194} 195 196elf_ei_class = { 197 'ELFCLASSNONE': 0, 'ELFCLASS32': 1, 'ELFCLASS64': 2 198} 199 200elf_ei_data = { 201 'ELFDATANONE': 0, 'ELFDATA2LSB': 1, 'ELFDATA2MSB': 2 202} 203 204elf_ei_osabi = { 205 # Official values. 206 'ELFOSABI_NONE': 0, 207 'ELFOSABI_HPUX': 1, 208 'ELFOSABI_NETBSD': 2, 209 'ELFOSABI_GNU': 3, 210 'ELFOSABI_HURD': 4, 211 'ELFOSABI_86OPEN': 5, 212 'ELFOSABI_SOLARIS': 6, 213 'ELFOSABI_AIX': 7, 214 'ELFOSABI_IRIX': 8, 215 'ELFOSABI_FREEBSD': 9, 216 'ELFOSABI_TRU64': 10, 217 'ELFOSABI_MODESTO': 11, 218 'ELFOSABI_OPENBSD': 12, 219 'ELFOSABI_OPENVMS': 13, 220 'ELFOSABI_NSK': 14, 221 'ELFOSABI_ARM': 97, 222 'ELFOSABI_STANDALONE': 255, 223 # Aliases. 224 'ELFOSABI_SYSV': 0, 225 'ELFOSABI_LINUX': 3, 226 'ELFOSABI_MONTEREY': 7 227} 228 229elf_ph_fields = [ 'p_align', 'p_filesz', 'p_flags', 'p_memsz', 'p_offset', 230 'p_paddr', 'p_type', 'p_vaddr' ] 231 232elf_ph_flags = { 233 'PF_X': 0x1, 'PF_W': 0x2, 'PF_R': 0x4 234} 235 236elf_ph_type = { 237 'PT_NULL': 0, 'PT_LOAD': 1, 'PT_DYNAMIC': 2, 'PT_INTERP': 3, 238 'PT_NOTE': 4, 'PT_SHLIB': 5, 'PT_PHDR': 6, 'PT_TLS': 7, 239 'PT_LOOS': 0x60000000, 'PT_HIOS': 0x6FFFFFFF, 240 'PT_SUNW_UNWIND': 0x6464E550, 'PT_GNU_EHFRAME': 0x6464E550, # dup 241 'PT_SUNWBSS': 0x6FFFFFFA, 'PT_SUNWSTACK': 0x6FFFFFFB, 242 'PT_SUNWDTRACE': 0x6FFFFFFC, 'PT_SUNWCAP': 0x6FFFFFFD, 243 'PT_LOPROC': 0x70000000, 'PT_HIPROC': 0x7FFFFFFF 244} 245 246elf_sh_type = { 247 'SHT_NULL': 0, 'SHT_PROGBITS': 1, 'SHT_SYMTAB': 2, 'SHT_STRTAB': 3, 248 'SHT_RELA': 4, 'SHT_HASH': 5, 'SHT_DYNAMIC': 6, 'SHT_NOTE': 7, 249 'SHT_NOBITS': 8, 'SHT_REL': 9, 'SHT_SHLIB': 10, 'SHT_DYNSYM': 11, 250 'SHT_INIT_ARRAY': 14, 'SHT_FINI_ARRAY': 15, 'SHT_PREINIT_ARRAY': 16, 251 'SHT_GROUP': 17, 'SHT_SYMTAB_SHNDX': 18, 'SHT_LOOS': 0x60000000, 252 'SHT_HIOS': 0x6fffffff, 'SHT_LOPROC': 0x70000000, 253 'SHT_HIPROC': 0x7fffffff, 'SHT_LOUSER': 0x80000000, 254 'SHT_HIUSER': 0xffffffff, 255 # OS specific types 256 'SHT_SUNW_dof': 0x6FFFFFF4, 'SHT_SUNW_cap': 0x6FFFFFF5, 257 'SHT_SUNW_SIGNATURE': 0x6FFFFFF6, 258 'SHT_SUNW_ANNOTATE': 0x6FFFFFF7, 'SHT_GNU_LIBLIST': 0x6ffffff7, # dup 259 'SHT_SUNW_DEBUGSTR': 0x6FFFFFF8, 'SHT_SUNW_DEBUG': 0x6FFFFFF9, 260 'SHT_SUNW_move': 0x6FFFFFFA, 'SHT_SUNW_COMDAT': 0x6FFFFFFB, 261 'SHT_SUNW_syminfo': 0x6FFFFFFC, 262 'SHT_GNU_verdef': 0x6ffffffd, 'SHT_SUNW_verdef': 0x6ffffffd, # dup 263 'SHT_GNU_verneed': 0x6ffffffe, 'SHT_SUNW_verneed': 0x6ffffffe, # dup 264 'SHT_GNU_versym': 0x6fffffff, 'SHT_SUNW_versym': 0x6fffffff, # dup 265 # Processor specific types 266 'SHT_IA_64_EXT': 0x70000000, 'SHT_IA_64_UNWIND': 0x70000001 267} 268 269elf_sh_flags = { 270 'SHF_WRITE': 0x1, 'SHF_ALLOC': 0x2, 'SHF_EXECINSTR': 0x4, 271 'SHF_MERGE': 0x10, 'SHF_STRINGS': 0x20, 'SHF_INFO_LINK': 0x40, 272 'SHF_LINK_ORDER': 0x80, 'SHF_OS_NONCONFORMING': 0x100, 273 'SHF_GROUP': 0x200, 'SHF_TLS': 0x400, 'SHF_MASKOS': 0x0ff00000, 274 'SHF_MASKPROC': 0xf0000000 275} 276 277elf_st_bindings = { 278 'STB_LOCAL': 0, 'STB_GLOBAL': 1, 'STB_WEAK': 2 279} 280 281elf_st_flags = { 282 'SHF_WRITE': 1, 'SHF_ALLOC': 2, 'SHF_EXECINSTR': 4 283} 284 285elf_st_types = { 286 'STT_NOTYPE': 0, 'STT_OBJECT': 1, 'STT_FUNC': 2, 'STT_SECTION': 3, 287 'STT_FILE': 3 288} 289 290elf_syminfo_flags = { 291 'SYMINFO_FLG_DIRECT': 1, 292 'SYMINFO_FLG_PASSTHRU': 2, 'SYMINFO_FLG_FILTER': 2, # dup 293 'SYMINFO_FLG_COPY': 4, 'SYMINFO_FLG_LAZYLOAD': 8, 294 'SYMINFO_FLG_DIRECTBIND': 0x10, 'SYMINFO_FLG_NOEXTDIRECT': 0x20, 295 'SYMINFO_FLG_AUXILIARY': 0x40 296} 297 298elf_syminfo_boundto_types = { 299 'SYMINFO_BT_SELF': 0xFFFF, 'SYMINFO_BT_PARENT': 0xFFFE, 300 'SYMINFO_BT_NONE': 0xFFFD, 'SYMINFO_BT_EXTERN': 0xFFFC 301} 302 303# Defaults 304 305defaults = { 306 # ElfDyn structures 307 'd_tag': 'DT_NULL', 308 'd_un': '0', 309 310 # fields in an ELf Executable Header 311 'e_ehsize': None, 312 'e_entry': '0', 313 'e_flags': [ '0' ], 314 'e_ident': None, 315 'e_machine': 'EM_NONE', 316 'e_phentsize': None, 317 'e_phnum': None, 318 'e_phoff': None, 319 'e_shentsize': None, 320 'e_shnum': None, 321 'e_shoff': None, 322 'e_shstrndx': None, 323 'e_type': 'ET_NONE', 324 'e_version': 'EV_CURRENT', 325 # e_ident bytes 326 'ei_class': 'ELFCLASS32', 327 'ei_data': 'ELFDATA2LSB', 328 'ei_version': 'EV_CURRENT', 329 'ei_osabi': 'ELFOSABI_NONE', 330 'ei_abiversion': '0', 331 # File-wide defaults 332 'elf_fillchar': '0', 333 # Elf Notes 334 'n_namesz': None, 335 'n_descsz': None, 336 'n_type': '0', 337 'n_data': [ "", "" ], 338 # Phdr 339 'p_align': '1', 340 'p_filesz': '0', 341 'p_memsz': '0', 342 'p_flags': [ '0' ], 343 'p_offset': '0', 344 'p_paddr': '0', 345 'p_type': 'PT_NULL', 346 'p_vaddr': '0', 347 # Shdr 348 'sh_addr': '0', 349 'sh_addralign': None, 350 'sh_data': [], 351 'sh_entsize': '0', 352 'sh_flags': [ '0' ], 353 'sh_info': '0', 354 'sh_index': None, 355 'sh_link': '0', 356 'sh_name': '0', 357 'sh_offset': None, 358 'sh_size': None, 359 'sh_type': 'SHT_NULL', 360 # Verdaux 361 'vda_name': 0, 362 'vda_next': 0, 363 # Verdef 364 'vd_version': 1, 365 'vd_flags': 0, 366 'vd_ndx': 0, 367 'vd_cnt': 0, 368 'vd_hash': 0, 369 'vd_aux': 0, 370 'vd_next': 0, 371 # Vernaux 372 'vna_hash': 0, 373 'vna_flags': 0, 374 'vna_other': 0, 375 'vna_name': 0, 376 'vna_next': 0, 377 # Verneed 378 'vn_version': 1, 379 'vn_cnt': 0, 380 'vn_file': 0, 381 'vn_aux': 0, 382 'vn_next': 0 383} 384 385# 386# Module wide constants. 387# 388 389ELFCLASS32 = elf_ei_class['ELFCLASS32'] 390ELFDATA2LSB = elf_ei_data['ELFDATA2LSB'] 391SHT_NOBITS = elf_sh_type['SHT_NOBITS'] 392SHT_NULL = elf_sh_type['SHT_NULL'] 393SHT_STRTAB = elf_sh_type['SHT_STRTAB'] 394SHN_LORESERVE= 0xFF00 395SHN_XINDEX = 0xFFFF 396# 397# Helper functions. 398# 399 400def get(d, key, default): 401 """Retrieve the value of 'key' from YAML dictionary 'd'. 402 403 The return value is guaranteed to be not 'None'. 404 """ 405 v = d.get(key, default) 406 if v is None: 407 v = default 408 return v 409 410def encode(d, key, default, mapping): 411 """Return the numeric value of d[key] in map 'mapping'.""" 412 413 v = get(d, key, default) 414 try: 415 return mapping[v] 416 except KeyError: 417 return int(v) 418 419def encode_flags(flags, m): 420 """Convert 'flags' to a single numeric value using mapping 'm'.""" 421 try: 422 v = long(flags) 423 return v 424 except: 425 pass 426 v = 0L 427 for f in flags: 428 try: 429 t = long(m[f]) 430 except KeyError: 431 t = long(f) 432 v |= t 433 return v 434 435def check_dict(d, l, node=None): 436 """Check a dictionary for unknown keys.""" 437 unknown = [] 438 for k in d.keys(): 439 if k not in l: 440 unknown.append(k) 441 if len(unknown) > 0: 442 raise ElfError(node, "{%s} Unknown key(s) %s" % \ 443 (node.tag, unknown)) 444 445# 446# Helper classes. 447# 448 449class ElfStrTab: 450 """A ELF string table. 451 452 This class manages strings in an ELF string table section. 453 """ 454 455 def __init__(self, strs=None): 456 """Initialize a string table from a list of strings.""" 457 self.offset = 1 # reserve space for initial null byte 458 self.htab = {} 459 if type(strs) == types.StringType: # one string 460 self.add(strs) 461 elif type(strs) == types.ListType: # list of strings 462 for s in strs: 463 self.add(s) 464 465 def add(self, str): 466 """Add a string to the string table. 467 468 Returns the offset of the string in the ELF section.""" 469 try: 470 return self.lookup(str) 471 except KeyError: 472 self.htab[str] = offset = self.offset 473 self.offset += len(str) + 1 # Keep space for a NUL. 474 return offset 475 476 def bits(self): 477 """Return the contents of an ELF string table.""" 478 479 l = self.htab.items() 480 l.sort(lambda x, y: cmp(x[1],y[1])) # Order by string offset. 481 ls = [""] # initial NUL 482 for (ss,oo) in l: 483 ls.append(ss) 484 return "\000".join(ls) + "\000" # Add trailing NULs 485 486 def lookup(self, str): 487 """Return the ELF string table offset for string 'str'.""" 488 489 return self.htab[str] 490 491 492class ElfType: 493 """A base type for ELF type descriptors. 494 495 Derived classes are expected to provide the following attributes: 496 497 'fields' -- a list of 4-typles (name, fn, lsz, msz). 498 499 'name' is the name of a field in the ELF structure. 500 501 'fn' is a convertor function, one of the functions 502 'do_(long,encode,flags)' below. 503 504 'msz' and 'lsz' provide the appropriate sizes when 505 generating a binary representation of the type. 506 """ 507 508 fields = None 509 def __init__(self, d, node): 510 """Initialize an ELF datatype from a YAML description. 511 512 Arguments: 513 d -- a dictionary containing name/value pairs specified 514 in the text description. 515 node -- YAML parser node for this element. 516 """ 517 518 keys = map(lambda t: t[0], self.fields) 519 check_dict(d, keys, node) 520 for f in self.fields: 521 name = f[0] 522 fn = f[1] 523 try: 524 v = fn(d, name) 525 setattr(self,f[0],v) 526 except: 527 raise ElfError(node, 528 'key: "%s" value: "%s" unrecognized.' % \ 529 (name, d[name])) 530 self._n = node # Save YAML node and associated value 531 self._d = d # for error reporting. 532 533 def __getitem__(self, attrib): 534 """Allow an ELF type to be treated like a dictionary.""" 535 536 return getattr(self, attrib) 537 538 def bits(self, formatchar, elfclass): 539 """Convert an ELF type to its file representation.""" 540 541 format, args = self.getfields(elfclass) 542 return struct.pack(formatchar + format, *args) 543 544 def formatstring(self, elfclass): 545 """Return the format string for this type.""" 546 547 if elfclass == ELFCLASS32: 548 n = 2 549 else: 550 n = 3 551 return "".join(map (lambda t: t[n], self.fields)) 552 553 def content(self, elfclass): 554 """Return a tuple containing the values for an ELF type.""" 555 556 a = [] 557 if elfclass == ELFCLASS32: 558 n = 2 559 else: 560 n = 3 561 for t in self.fields: 562 if t[n] != "": 563 a.append(getattr(self, t[0])) 564 return tuple(a) 565 566 def getfields(self, elfclass): 567 """Describe the binary layout of the type. 568 569 Return a tuple (formatstring, *args) describing the 570 desired binary layout in the manner of the 'struct' 571 python library module. 572 """ 573 574 return (self.formatstring(elfclass), 575 self.content(elfclass)) 576 577 def layout(self, offset, elf): 578 """Perform any layout-time translation for an ELF type.""" 579 580 return offset 581 582 def size(self, elfclass): 583 """Return the size of the type in bytes. 584 585 The size returned is independent of the alignment needs of 586 the type. 587 """ 588 589 format = self.formatstring(elfclass) 590 sz = 0 591 for f in format: 592 if f == "B": 593 sz += 1 594 elif f == "H": 595 sz += 2 596 elif f == "I": 597 sz += 4 598 elif f == "Q": 599 sz += 8 600 elif f == "": 601 pass 602 else: 603 raise TypeError, "Invalid format char '%s'." % f 604 return sz 605 606 607# 608# Translation helper functions. 609# 610 611def do_string(d, n): 612 """Convert a YAML value to a Python string.""" 613 614 v = get(d, n, defaults[n]) 615 if v: 616 return str(v) 617 return v 618 619def do_long(d, n): 620 """Convert a YAML value to a Python 'long'.""" 621 622 v = get(d, n, defaults[n]) 623 if v: 624 return long(v) 625 return v 626 627def do_copy(d, n): 628 """Copy a YAML value without conversion.""" 629 630 v = get(d, n, defaults[n]) 631 return v 632 633def do_encode(xlate): 634 """Translate a YAML value according to mapping 'xlate'.""" 635 636 return lambda d, n, xl=xlate: encode(d, n, defaults[n], xl) 637 638def do_flags(xlate): 639 """Translate a list of flags according to mapping 'xlate'.""" 640 641 return lambda d, n, xl=xlate: encode_flags(get(d, n, defaults[n]), xl) 642 643# 644# Definitions of ELF types. 645# 646 647class ElfCap(ElfType): 648 """A representation of an ELF Cap structure. 649 650 YAML tag: !Cap 651 """ 652 653 fields = [ 654 ('c_tag', do_encode(elf_cap_tag), "I", "Q"), 655 ('c_un', do_long, "I", "Q") 656 ] 657 def __init__(self, cap, node): 658 ElfType.__init__(self, cap, node) 659 660 661class ElfDyn(ElfType): 662 """A representation of an ELF Dyn structure. 663 664 YAML tag: !Dyn 665 """ 666 667 fields = [ 668 ('d_tag', do_encode(elf_d_tag), "I", "Q"), 669 ('d_un', do_long, "I", "Q") 670 ] 671 672 def __init__(self, d, node): 673 ElfType.__init__(self, d, node) 674 675 676class ElfEhdrIdent(ElfType): 677 """A representation for the 'ident' field of an ELF Ehdr. 678 679 YAML tag: !Ident 680 """ 681 682 fields = [ 683 ('ei_class', do_encode(elf_ei_class), "B", "B"), 684 ('ei_data', do_encode(elf_ei_data), "B", "B"), 685 ('ei_version', do_encode(elf_ei_version), "B", "B"), 686 ('ei_osabi', do_encode(elf_ei_osabi), "B", "B"), 687 ('ei_abiversion', do_long, "B", "B") 688 ] 689 690 def __init__(self, ei, node): 691 ElfType.__init__(self, ei, node) 692 693 def bits(self, format, elfclass): 694 f, args = self.getfields(elfclass) 695 s = "\x7FELF" 696 s += struct.pack(f + 'xxxxxxx', *args) 697 return s 698 699 700class ElfEhdr(ElfType): 701 """A representation of an ELF Executable Header. 702 703 YAML tag: !Ehdr 704 """ 705 706 fields = [ 707 ('e_ident', do_copy, "", ""), 708 ('e_type', do_encode(elf_ehdr_type), "H", "H"), 709 ('e_machine', do_encode(elf_ehdr_machine), "H", "H"), 710 ('e_version', do_encode(elf_ei_version), "I", "I"), 711 ('e_entry', do_long, "I", "Q"), 712 ('e_phoff', do_long, "I", "Q"), 713 ('e_shoff', do_long, "I", "Q"), 714 ('e_flags', do_flags(elf_ehdr_flags), "I", "I"), 715 ('e_ehsize', do_long, "H", "H"), 716 ('e_phentsize', do_long, "H", "H"), 717 ('e_phnum', do_long, "H", "H"), 718 ('e_shentsize', do_long, "H", "H"), 719 ('e_shnum', do_long, "H", "H"), 720 ('e_shstrndx', do_copy, "H", "H") 721 ] 722 723 def __init__(self, eh, node): 724 """Initialize an Ehdr structure. 725 726 If an 'ident' structure was not specified as part of 727 the YAML description, initialize it explicitly. 728 """ 729 730 ElfType.__init__(self, eh, node) 731 if self.e_ident is None: 732 self.e_ident = ElfEhdrIdent({}, node) 733 734 def layout(self, offset, elf): 735 """Layout an ELF Ehdr. 736 737 This method will fill in defaults and/or compute 738 values for fields that were not specified in the YAML 739 description. 740 """ 741 742 elfclass = elf.elfclass() 743 if elfclass == ELFCLASS32: 744 e_ehsize = 52 745 e_phentsize = 32 746 e_shentsize = 40 747 alignment = 4 748 else: # 64 bit sizes 749 e_ehsize = 64 750 e_phentsize = 56 751 e_shentsize = 64 752 alignment = 8 753 754 if self.e_ehsize is None: 755 self.e_ehsize = e_ehsize 756 757 # Compute e_phnum if needed. 758 if self.e_phnum is None: 759 self.e_phnum = len(elf.elf_phdrtab) 760 761 # Compute a value for the e_phentsize field. 762 if self.e_phentsize is None: 763 if self.e_phnum: 764 self.e_phentsize = e_phentsize 765 else: 766 self.e_phentsize = 0 767 768 # Set the e_shentsize field. 769 if self.e_shentsize is None: 770 self.e_shentsize = e_shentsize 771 772 # The program header defaults to just after the ELF header. 773 if self.e_phoff is None: 774 if self.e_phnum > 0: 775 self.e_phoff = \ 776 (self.e_ehsize + (alignment - 1)) & \ 777 ~(alignment - 1) 778 else: 779 self.e_phoff = 0 780 781 # compute e_shnum 782 self.nsections = elf.elf_sections.get_shnum() 783 if self.nsections > 0: 784 if self.e_shstrndx is None: 785 self.e_shstrndx = '.shstrtab' 786 if type(self.e_shstrndx) == types.StringType: 787 self.e_shstrndx = \ 788 elf.elf_sections.get_index(self.e_shstrndx) 789 elif type(self.e_shstrndx) == types.IntType or \ 790 type(self.e_shstrndx) == types.LongType: 791 pass 792 else: 793 raise ElfError(self._n, "Unparseable e_shstrndx field.") 794 if self.e_shstrndx is None: 795 raise ElfError(self._n, 796 'Cannot determine section ' + \ 797 'name string table index.') 798 else: 799 if self.e_shstrndx is None: 800 self.e_shstrndx = 0 801 802 if self.e_shnum is None: 803 self.e_shnum = self.nsections 804 805 # section data comes after the program header by default. The 806 # section header table is placed after all section data. 807 808 if self.e_phnum > 0: 809 offset = self.e_phoff + self.e_phnum * self.e_phentsize 810 else: 811 offset = self.e_ehsize 812 offset = elf.elf_sections.layout(offset, elf) 813 if self.e_shoff is None: 814 if self.nsections > 0: 815 self.e_shoff = (offset + (alignment-1)) & \ 816 ~(alignment-1) 817 else: 818 self.e_shoff = 0 819 820 if self.nsections >= SHN_LORESERVE: 821 elf.elf_sections.set_extended_shnum(self.nsections) 822 self.e_shnum = 0 823 if self.e_shstrndx >= SHN_XINDEX: 824 elf.elf_sections.set_extended_shstrndx(self.e_shstrndx) 825 self.e_shstrndx = SHN_XINDEX 826 827 def bits(self, formatchar, elfclass): 828 """Return the file representation of an Elf Ehdr.""" 829 830 s = self.e_ident.bits(formatchar, elfclass) 831 s += ElfType.bits(self, formatchar, elfclass) 832 833 return s 834 835 836class ElfLong: 837 """Wrapper around a python Int/Long.""" 838 839 def __init__(self, v): 840 self._v = long(v) 841 842 def bits(self, formatchar, elfclass): 843 """Return the file representation for this object. 844 845 Depending on the number of bits needed to represent 846 the number, the returned bits would be either 4 or 847 8 bytes wide. 848 """ 849 850 if self._v > 0xFFFFFFFFL: 851 f = formatchar + "Q" 852 else: 853 f = formatchar + "I" 854 return struct.pack(f, self._v) 855 856 857class ElfMove(ElfType): 858 """A representation of an Elf Move type. 859 860 YAML tag: !Move 861 """ 862 863 fields = [ 864 ('m_value', do_long, "I", "I"), 865 ('m_info', do_long, "I", "Q"), 866 ('m_poffset', do_long, "I", "Q"), 867 ('m_repeat', do_long, "H", "H"), 868 ('m_stride', do_long, "H", "H") 869 ] 870 871 def __init__(self, move, node): 872 ElfType.__init__(self, move, node) 873 874 875class ElfNote(ElfType): 876 """A representation of an Elf Note type. 877 878 YAML tag: !Note 879 880 The data in the note is held in YAML node named 'n_data' which is 881 a pair of strings, one for the note's name field and one for the 882 description. 883 884 If the fields 'n_namesz' and 'n_descz' aren't specified, they 885 are computed from the contents of 'n_data'. 886 """ 887 888 fields = [ 889 ('n_namesz', do_long, "I", "I"), 890 ('n_descsz', do_long, "I", "I"), 891 ('n_type', do_long, "I", "I"), 892 ('n_data', do_copy, "", "") 893 ] 894 895 def __init__(self, note, node): 896 ElfType.__init__(self, note, node) 897 self._note = note 898 899 def layout(self, offset, elfclass): 900 if len(self.n_data) != 2: 901 raise ElfError(node, "Note data not a pair of strings.") 902 903 for nd in self.n_data: 904 if isinstance(nd, ElfType): 905 nd.layout(offset, elfclass) 906 907 if self.n_namesz is None: 908 self.n_namesz = len(self.n_data[0]) 909 if self.n_descsz is None: 910 self.n_descsz = len(self.n_data[1]) 911 912 def bits(self, format, elfclass): 913 b = ElfType.bits(self, format, elfclass) 914 nbits = str(self.n_data[0]) 915 dbits = str(self.n_data[1]) 916 return b + nbits + dbits 917 918 919class ElfPhdr(ElfType): 920 """A representation of an ELF Program Header Table entry. 921 922 YAML tag: !Phdr 923 """ 924 925 fields = [ # NOTE: class-dependent field ordering 926 ('p_align', do_long), 927 ('p_filesz', do_long), 928 ('p_flags' , do_flags(elf_ph_flags), ), 929 ('p_memsz' , do_long), 930 ('p_offset', do_long), 931 ('p_paddr' , do_long), 932 ('p_type' , do_encode(elf_ph_type)), 933 ('p_vaddr' , do_long) 934 ] 935 936 def __init__(self, ph, node): 937 ElfType.__init__(self, ph, node) 938 939 def to_string(self): 940 """Helper during debugging.""" 941 942 s = "Phdr(type:%(p_type)d,flags:%(p_flags)d," \ 943 "offset:%(p_offset)ld,vaddr:%(p_vaddr)ld," \ 944 "paddr:%(p_paddr)ld,filesz:%(p_filesz)ld," \ 945 "memsz:%(p_memsz)ld)" % self 946 return s 947 948 def bits(self, formatchar, elfclass): 949 """Return the file representation of a Phdr.""" 950 951 f = formatchar 952 # Phdr structures are laid out in a class-dependent way 953 if elfclass == ELFCLASS32: 954 f += "IIIIIIII" 955 s = struct.pack(f, 956 self.p_type, 957 self.p_offset, 958 self.p_vaddr, 959 self.p_paddr, 960 self.p_filesz, 961 self.p_memsz, 962 self.p_flags, 963 self.p_align) 964 else: 965 f += "IIQQQQQQ" 966 s = struct.pack(f, 967 self.p_type, 968 self.p_flags, 969 self.p_offset, 970 self.p_vaddr, 971 self.p_paddr, 972 self.p_filesz, 973 self.p_memsz, 974 self.p_align) 975 return s 976 977class ElfRel(ElfType): 978 """A representation of an ELF Rel type. 979 980 YAML tag: !Rel 981 """ 982 983 fields = [ 984 ('r_offset', do_long, "I", "Q"), 985 ('r_info', do_long, "I", "Q") 986 ] 987 988 def __init__(self, rel, node): 989 ElfType.__init__(self, rel, node) 990 991 992class ElfRela(ElfType): 993 """A representation of an ELF Rela type. 994 995 YAML tag: !Rela 996 """ 997 998 fields = [ 999 ('r_offset', do_long, "I", "Q"), 1000 ('r_info', do_long, "I", "Q"), 1001 ('r_addend', do_long, "I", "Q") 1002 ] 1003 1004 def __init__(self, rela, node): 1005 ElfType.__init__(self, rela, node) 1006 1007 1008class ElfSection(ElfType): 1009 """A representation of an ELF Section. 1010 1011 YAML tag: !Section 1012 1013 A section description consists of the fields that make up an ELF 1014 section header entry and an additional field 'sh_data' that 1015 contains the data associated with this section. 1016 1017 'sh_data' may be a YAML string, or a YAML list of items that 1018 comprise the content of the section. 1019 """ 1020 1021 fields = [ 1022 ('sh_name', do_string, "I", "I"), 1023 ('sh_type', do_encode(elf_sh_type), "I", "I"), 1024 ('sh_flags', do_flags(elf_sh_flags), "I", "Q"), 1025 ('sh_addr', do_long, "I", "Q"), 1026 ('sh_offset', do_long, "I", "Q"), 1027 ('sh_size', do_long, "I", "Q"), 1028 ('sh_link', do_long, "I", "I"), 1029 ('sh_info', do_long, "I", "I"), 1030 ('sh_addralign', do_copy, "I", "Q"), 1031 ('sh_entsize', do_long, "I", "Q"), 1032 ('sh_data', do_copy, "", ""), 1033 ('sh_index', do_long, "", "") 1034 ] 1035 1036 def __init__(self, shdr, node): 1037 """Initialize a section descriptor.""" 1038 1039 ElfType.__init__(self, shdr, node) 1040 if type(self.sh_data) != types.ListType: 1041 self.sh_data = list(self.sh_data) 1042 if self.sh_addralign is None: 1043 if self.sh_type == SHT_NULL or self.sh_type == SHT_NOBITS: 1044 self.sh_addralign = 0 1045 else: 1046 self.sh_addralign = 1 1047 else: 1048 if (self.sh_addralign == 0 or \ 1049 (self.sh_addralign & (self.sh_addralign - 1)) != 0): 1050 raise ElfError(node, 1051 "'sh_addralign' not a power of two.") 1052 self._data = None # 'cache' of translated data 1053 self._strtab = None 1054 1055 def to_string(self): 1056 """Helper function during debugging.""" 1057 1058 return "Section(name:%(sh_name)s,type:%(sh_type)d," \ 1059 "flags:%(sh_flags)x,addr:%(sh_addr)d,"\ 1060 "offset:%(sh_offset)d,size:%(sh_size)d," \ 1061 "link:%(sh_link)d,info:%(sh_info)d," \ 1062 "addralign:%(sh_addralign)d,entsize:%(sh_entsize)d)" % \ 1063 self 1064 1065 def make_strtab(self): 1066 """Create a string table from section contents.""" 1067 1068 self._strtab = ElfStrTab(self.sh_data) 1069 1070 def string_to_index(self, name): 1071 """Convert 'name' to an offset inside a string table. 1072 1073 Only valid for sections of type SHT_STRTAB.""" 1074 1075 if self._strtab: 1076 return self._strtab.lookup(name) 1077 raise ElfError(None, 'Cannot translate "%s" to an index.' % name) 1078 1079 def bits(self, formatchar, elfclass): 1080 raise AssertionError, "Section objects should use " \ 1081 "databits() or headerbits()" 1082 1083 def layout(self, offset, elf): 1084 """Prepare an ELF section for output.""" 1085 1086 if type(self.sh_name) == types.StringType: 1087 # first try convert it to a long 1088 try: 1089 self.sh_name = long(self.sh_name) 1090 except ValueError: # lookup in string table 1091 try: 1092 self.sh_name = \ 1093 elf.section_name_index(self.sh_name) 1094 except KeyError: 1095 raise ElfError(self._n, 1096 "Section name '%s' not in string table." % \ 1097 self.sh_name) 1098 # give a chance for the contents of a section to xlate strings 1099 for d in self.sh_data: 1100 if isinstance(d, ElfType): 1101 d.layout(offset, elf) 1102 # compute the space used by the section data 1103 self._data = self.databits(elf.formatchar(), elf.elfclass()) 1104 1105 align = self.sh_addralign 1106 if align == 0: 1107 align = 1 1108 if self.sh_type == SHT_NULL or self.sh_type == SHT_NOBITS: 1109 isnulltype = 1 1110 else: 1111 isnulltype = 0 1112 1113 offset = (offset + (align - 1)) & ~(align - 1) 1114 if self.sh_size is None: 1115 if isnulltype: 1116 self.sh_size = 0 1117 else: 1118 self.sh_size = len(self._data) 1119 if self.sh_offset is None: 1120 if isnulltype: 1121 self.sh_offset = 0 1122 else: 1123 self.sh_offset = offset 1124 if isnulltype: # ignore bits for null types 1125 return offset 1126 return offset + len(self._data) 1127 1128 def databits(self, formatchar, elfclass): 1129 """Return the contents of a section.""" 1130 1131 if self._data: 1132 return self._data 1133 # special-case string table handling 1134 if self.sh_type == SHT_STRTAB: 1135 return self._strtab.bits() 1136 # 'normal' section 1137 s = "" 1138 for d in self.sh_data: 1139 if isinstance(d, ElfType): 1140 s += d.bits(formatchar, elfclass) 1141 elif isinstance(d, types.LongType): 1142 s += struct.pack(formatchar + "Q", d) 1143 elif isinstance(d, types.IntType): 1144 s += struct.pack(formatchar + "I", d) 1145 else: 1146 s += str(d) 1147 return s 1148 1149 def headerbits(self, formatchar, elfclass): 1150 """Return the file representation of the section header.""" 1151 1152 return ElfType.bits(self, formatchar, elfclass) 1153 1154 1155class ElfSym(ElfType): 1156 """A representation for an ELF Symbol type. 1157 1158 YAML tag: !Sym 1159 """ 1160 1161 fields = [ # NOTE: class-dependent layout. 1162 ('st_info', do_long, "B", "B"), 1163 ('st_name', do_string, "I", "I"), 1164 ('st_other', do_long, "B", "B"), 1165 ('st_shndx', do_string, "H", "H"), 1166 ('st_size', do_long, "I", "Q"), 1167 ('st_value', do_long, "I", "Q") 1168 ] 1169 1170 def __init__(self, sym, node): 1171 ElfType.__init__(self, sym, node) 1172 1173 def bits(self, format, elfclass): 1174 """Return the file representation for an ELF Sym.""" 1175 1176 if elfclass == ELFCLASS32: 1177 s = struct.pack(format + "IIIBBH", 1178 self.st_name, 1179 self.st_value, 1180 self.st_size, 1181 self.st_info, 1182 self.st_other, 1183 self.st_shndx) 1184 else: 1185 s = struct.pack(format + "IBBHQQ", 1186 self.st_name, 1187 self.st_info, 1188 self.st_other, 1189 self.st_shndx, 1190 self.st_value, 1191 self.st_size) 1192 return s 1193 1194 def layout(self, offset, elf): 1195 """Perform layout-time conversions for an ELF Sym. 1196 1197 String valued fields are converted to offsets into 1198 string tables. 1199 """ 1200 1201 if type(self.st_shndx) == types.StringType: 1202 self.st_shndx = \ 1203 elf.elf_sections.get_index(self.st_shndx) 1204 if self.st_shndx is None: 1205 raise ElfError(self._n, "Untranslateable 'st_shndx' " + \ 1206 "value \"%s\"." % self.st_shndx) 1207 1208 if type(self.st_name) == types.StringType: 1209 try: 1210 strtab = \ 1211 elf.elf_sections[self.st_shndx]._strtab 1212 except IndexError: 1213 raise ElfError(self._n, "'st_shndx' out of range") 1214 if strtab is None: 1215 raise ElfError(self._n, "'st_shndx' not of type STRTAB.") 1216 1217 try: 1218 self.st_name = strtab.lookup(self.st_name) 1219 except KeyError: 1220 raise ElfError(self._n, 1221 'unknown string "%s"' % self.st_name) 1222 return offset 1223 1224 1225class ElfSyminfo(ElfType): 1226 """A representation of an ELF Syminfo type. 1227 1228 YAML tag: !Syminfo 1229 """ 1230 1231 fields = [ 1232 ('si_boundto', do_encode(elf_syminfo_boundto_types), "H", "H"), 1233 ('si_flags', do_flags(elf_syminfo_flags), "H", "H") 1234 ] 1235 1236 def __init__(self, syminfo, node): 1237 ElfType.__init__(self, syminfo, node) 1238 1239 1240class ElfVerdaux(ElfType): 1241 """A representation of an ELF Verdaux type.""" 1242 1243 fields = [ 1244 ('vda_name', do_long, "I", "I"), 1245 ('vda_next', do_long, "I", "I") 1246 ] 1247 1248 def __init__(self, verdaux, node): 1249 ElfType.__init__(self, verdaux, node) 1250 1251 1252class ElfVerdef(ElfType): 1253 """A representation of an ELF Verdef type.""" 1254 1255 fields = [ 1256 ('vd_version', do_long, "H", "H"), 1257 ('vd_flags', do_long, "H", "H"), 1258 ('vd_ndx', do_long, "H", "H"), 1259 ('vd_cnt', do_long, "H", "H"), 1260 ('vd_hash', do_long, "I", "I"), 1261 ('vd_aux', do_long, "I", "I"), 1262 ('vd_next', do_long, "I", "I") 1263 ] 1264 1265 def __init__(self, verdef, node): 1266 ElfType.__init__(self, verdef, node) 1267 1268 1269class ElfVernaux(ElfType): 1270 """A representation of an ELF Vernaux type.""" 1271 1272 fields = [ 1273 ('vna_hash', do_long, "I", "I"), 1274 ('vna_flags', do_long, "H", "H"), 1275 ('vna_other', do_long, "H", "H"), 1276 ('vna_name', do_long, "I", "I"), 1277 ('vna_next', do_long, "I", "I") 1278 ] 1279 1280 def __init__(self, vernaux, node): 1281 ElfType.__init__(self, vernaux, node) 1282 1283class ElfVerneed(ElfType): 1284 """A representation of an ELF Verneed type.""" 1285 1286 fields = [ 1287 ('vn_version', do_long, "H", "H"), 1288 ('vn_cnt', do_long, "H", "H"), 1289 ('vn_file', do_long, "I", "I"), 1290 ('vn_aux', do_long, "I", "I"), 1291 ('vn_next', do_long, "I", "I") 1292 ] 1293 1294 def __init__(self, verneed, node): 1295 ElfType.__init__(self, verneed, node) 1296 1297 1298# 1299# Aggregates 1300# 1301 1302class ElfPhdrTable: 1303 """A representation of an ELF Program Header Table. 1304 1305 A program header table is a list of program header entry sections. 1306 """ 1307 1308 def __init__(self, phdr): 1309 """Initialize a program header table object. 1310 1311 Argument 'phdr' is a list of parsed ElfPhdr objects. 1312 """ 1313 1314 self.pht_data = [] 1315 for ph in phdr: 1316 if type(ph) == types.DictType: 1317 ph = ElfPhdr(ph) 1318 elif not isinstance(ph, ElfPhdr): 1319 raise ElfError(ph.node, 1320 "Program Header Table " 1321 "contains non header data.") 1322 self.pht_data.append(ph) 1323 1324 def bits(self, formatchar, elfclass): 1325 """Return the file representation of the Phdr table.""" 1326 1327 s = "" 1328 for d in self.pht_data: 1329 s += d.bits(formatchar, elfclass) 1330 return s 1331 1332 def __len__(self): 1333 """Return the number of program header table entries.""" 1334 1335 return len(self.pht_data) 1336 1337 def __iter__(self): 1338 """Return an iterator for traversing Phdr entries.""" 1339 1340 return self.pht_data.__iter__() 1341 1342 1343class ElfSectionList: 1344 """A list of ELF sections.""" 1345 1346 def __init__(self, shlist): 1347 """Initialize an ELF section list. 1348 1349 Argument 'shlist' is a list of parser ElfSection 1350 objects. 1351 """ 1352 1353 self.shl_sections = shlist 1354 self.shl_sectionnames = [] 1355 self.shl_nentries = len(shlist) 1356 1357 for sh in shlist: 1358 if not isinstance(sh, ElfSection): 1359 raise ElfError(None, 1360 """Section 'sections' contains 1361 unrecognized data.""") 1362 if sh.sh_index is not None: 1363 if self.shl_nentries <= sh.sh_index: 1364 self.shl_nentries = sh.sh_index + 1 1365 self.shl_sectionnames.append((sh.sh_name, sh.sh_index)) 1366 if sh.sh_type == SHT_STRTAB: # a string table 1367 sh.make_strtab() 1368 1369 def __len__(self): 1370 """Return the number of ELF sections.""" 1371 1372 return len(self.shl_sections) 1373 1374 def __iter__(self): 1375 """Iterate through ELF sections.""" 1376 1377 return self.shl_sections.__iter__() 1378 1379 def __getitem__(self, ind): 1380 """Retrieve the ELF section at index 'ind'.""" 1381 1382 try: 1383 return self.shl_sections[ind] 1384 except IndexError: 1385 for sh in self.shl_sections: 1386 if sh.sh_index == ind: 1387 return sh 1388 raise IndexError, "no section at index %d" % ind 1389 1390 def layout(self, offset, elf): 1391 """Compute the layout for section.""" 1392 1393 if len(self.shl_sections) == 0: 1394 return 0 1395 for sh in self.shl_sections: # layout sections 1396 offset = sh.layout(offset, elf) 1397 return offset 1398 1399 def get_index(self, name): 1400 """Return the section index for section 'name', or 'None'.""" 1401 1402 c = 0 1403 for (n,i) in self.shl_sectionnames: 1404 if n == name: 1405 if i is None: 1406 return c 1407 else: 1408 return i 1409 c += 1 1410 return None 1411 1412 def get_shnum(self): 1413 """Retrieve the number of sections in this container.""" 1414 1415 return self.shl_nentries 1416 1417 def set_extended_shnum(self, shnum): 1418 """Set the extended section number.""" 1419 1420 sh = self.shl_sections[0] 1421 sh.sh_size = shnum 1422 1423 def set_extended_shstrndx(self, strndx): 1424 """Set the extended string table index.""" 1425 1426 sh = self.shl_sections[0] 1427 sh.sh_link = strndx 1428 1429class Elf: 1430 """A representation of an ELF object.""" 1431 1432 def __init__(self, yamldict, ehdr, phdrtab, sections): 1433 self._d = yamldict 1434 self._n = None 1435 self.elf_ehdr = ehdr 1436 self.elf_phdrtab = phdrtab 1437 self.elf_sections = sections 1438 self.elf_fillchar = long(get(yamldict, 'elf_fillchar', 1439 defaults['elf_fillchar'])) 1440 def byteorder(self): 1441 """Return the byteorder for this ELF object.""" 1442 return self.elf_ehdr.e_ident.ei_data 1443 1444 def elfclass(self): 1445 """Return the ELF class for this ELF object.""" 1446 return self.elf_ehdr.e_ident.ei_class 1447 1448 def formatchar(self): 1449 """Return the format character corresponding to the ELF 1450 byteorder.""" 1451 1452 if self.byteorder() == ELFCLASS32: 1453 return "<" 1454 else: 1455 return ">" 1456 1457 def layout(self): 1458 """Compute a file layout for this ELF object and update 1459 internal data structures.""" 1460 1461 self.elf_ehdr.layout(0, self) 1462 1463 1464 def section_name_index(self, name): 1465 """Compute index of section 'name' in the section name string table.""" 1466 1467 strndx = self.elf_ehdr.e_shstrndx 1468 if strndx is None: 1469 return None 1470 return self.elf_sections[strndx].string_to_index(name) 1471 1472 def write(self, fn): 1473 """Write out the file representation of an ELF object. 1474 1475 Argument 'fn' denotes the destination.""" 1476 1477 of = file(fn, 'w') 1478 1479 formatchar = self.formatchar() 1480 elfclass = self.elfclass() 1481 1482 # Write out the header 1483 of.write(self.elf_ehdr.bits(formatchar, elfclass)) 1484 1485 # Write out the program header table if present 1486 if self.elf_phdrtab: 1487 self.reposition(of, self.elf_ehdr.e_phoff) 1488 for ph in self.elf_phdrtab: 1489 of.write(ph.bits(formatchar, elfclass)) 1490 # Write out the sections 1491 if self.elf_sections: 1492 # First the contents of the sections 1493 for sh in self.elf_sections: 1494 if sh.sh_type == SHT_NULL or sh.sh_type == SHT_NOBITS: 1495 continue 1496 self.reposition(of, sh.sh_offset) 1497 of.write(sh.databits(formatchar, elfclass)) 1498 # Then the header table 1499 self.reposition(of, self.elf_ehdr.e_shoff) 1500 for sh in self.elf_sections: 1501 if sh.sh_index: 1502 new_offset = sh.sh_index * self.elf_ehdr.e_shentsize + \ 1503 self.elf_ehdr.e_shoff 1504 self.reposition(of, new_offset) 1505 of.write(sh.headerbits(formatchar, elfclass)) 1506 of.close() 1507 1508 def reposition(self, f, offset): 1509 """Reposition file `f' to offset `offset', filling gaps with 1510 the configured fill character as needed.""" 1511 1512 pos = f.tell() 1513 if offset == pos: 1514 return 1515 if offset < pos or (offset > pos and self.elf_fillchar == 0): 1516 f.seek(offset, 0) 1517 return 1518 s = ("%c" % self.elf_fillchar) * (offset - pos) 1519 f.write(s) 1520 1521 1522# 1523# YAML Parser configuration and helpers. 1524# 1525 1526yaml_tags = [ 1527 (u'!Cap', ElfCap), 1528 (u'!Dyn', ElfDyn), 1529 (u'!Ehdr', ElfEhdr), 1530 (u'!Ident', ElfEhdrIdent), 1531 (u'!Move', ElfMove), 1532 (u'!Note', ElfNote), 1533 (u'!Phdr', ElfPhdr), 1534 (u'!Rel', ElfRel), 1535 (u'!Rela', ElfRela), 1536 (u'!Section', ElfSection), 1537 (u'!Sym', ElfSym), 1538 (u'!Syminfo', ElfSyminfo), 1539 (u'!Verdaux', ElfVerdaux), 1540 (u'!Verdef', ElfVerdef), 1541 (u'!Vernaux', ElfVernaux), 1542 (u'!Verneed', ElfVerneed) ] 1543 1544def init_parser(): 1545 for t in yaml_tags: 1546 yaml.add_constructor(t[0], # lamdba: loader, node, class 1547 lambda l, n, c=t[1]: \ 1548 c(l.construct_mapping(n, deep=True), n)) 1549 1550def make_elf(yd): 1551 """Convert a YAML description `yd' of an ELF file into an 1552 ELF object.""" 1553 1554 try: 1555 eh = yd['ehdr'] 1556 except KeyError: 1557 eh = ElfEhdr({}, None) 1558 1559 phdrtab = ElfPhdrTable(get(yd, 'phdrtab', {})) 1560 sectionlist = ElfSectionList(get(yd, 'sections', {})) 1561 1562 return Elf(yd, eh, phdrtab, sectionlist) 1563 1564 1565# 1566# MAIN 1567# 1568 1569if __name__ == '__main__': 1570 parser = optparse.OptionParser(usage=usage, version=version, 1571 description=description) 1572 parser.add_option("-o", "--output", dest="output", 1573 help="write output to FILE [default: %default]", 1574 metavar="FILE", default="a.out") 1575 parser.add_option("-N", "--no-shstrtab", dest="do_shstrtab", 1576 help="do not create a string table section for " 1577 "section names if missing", action="store_false", 1578 metavar="BOOLEAN", default=True) 1579 parser.add_option("-U", "--no-shnundef", dest="do_shnundef", 1580 help="do not create a section header for index " 1581 "SHN_UNDEF if missing", action="store_false", 1582 metavar="BOOLEAN", default=True) 1583 1584 (options, args) = parser.parse_args() 1585 1586 if len(args) > 1: 1587 parser.error("only one input-file must be specified") 1588 1589 try: 1590 if args: 1591 stream = file(args[0], 'r') 1592 else: 1593 stream = sys.stdin 1594 except IOError, x: 1595 parser.error("cannot open stream: %s" % x) 1596 1597 init_parser() 1598 1599 try: 1600 elf = make_elf(yaml.load(stream)) 1601 elf.layout() 1602 elf.write(options.output) 1603 except yaml.YAMLError, x: 1604 parser.error("cannot parse stream: %s" % x) 1605 except ElfError, msg: 1606 print msg 1607 sys.exit(1) 1608 1609 1610 1611# Local Variables: 1612# mode: python 1613# tab-width: 4 1614# py-indent-offset: 4 1615# End: 1616