OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [tools/] [pyelf/] [elf.py] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
from aistruct import GFile, BitPoker, AIStruct
2
import StringIO
3
import sys
4
 
5
class Elf32Header(AIStruct):
6
        EI_MAGIC = [0x7f, ord('E'), ord('L'), ord('F')]
7
        EI_CLASS_32 = 1
8
        EI_CLASS_64 = 2
9
        EI_DATA_LSB = 1
10
        EI_DATA_MSB = 2
11
        EI_TYPE_NONE = 0
12
        EI_TYPE_REL = 1
13
        EI_TYPE_EXEC = 2
14
        EI_TYPE_DYN = 3
15
        EI_TYPE_CORE = 4
16
        EI_TYPE_NUM = 5
17
        EI_TYPE_LOPROC = 0xff00
18
        EI_TYPE_HIPROC = 0xffff
19
        MACHINE_NONE = 0
20
        MACHINE_SPARC = 2
21
        MACHINE_386 = 3
22
        MACHINE_MIPS = 8
23
        MACHINE_MIPS_RS4_BE = 10
24
        MACHINE_SPARC32PLUS = 18
25
        MACHINE_ARM = 40
26
        MACHINE_FAKE_ALPHA = 41
27
        MACHINE_SPARCV9 = 43
28
        MACHINE_IA_64 = 50
29
        MACHINE_ALPHA = 0x9026
30
        VERSION_NONE = 0
31
        VERSION_CURRENT = 1
32
 
33
        def __init__(self):
34
                AIStruct.__init__(self, AIStruct.SIZE32)
35
                self.setup(
36
                        ('UINT8', 'ei_magic', {'times': 4}),
37
                        ('UINT8', 'ei_class', {'names' : { 1: "ELF32", 2: "ELF64" }} ),
38
                        ('UINT8', 'ei_data', {'names' : { 1 : "2's complement, little endian", 2: "2's complement, big endian" }}),
39
                        ('UINT8', 'ei_version', {'names' : { 1 : "1 (current)" }}),
40
                        ('UINT8', 'ei_osabi', { 'names' : { 0 : "UNIX - System V", 1 : "HP-UX Operating System", 255 : "Standalone application"}}),
41
                        ('UINT8', 'ei_abiversion'),
42
                        ('UINT8', 'ei_padding', {'times': 7}),
43
                        ('UINT16', 'e_type', { 'names' : { 2 : "EXEC (Executable file)" }} ),
44
                        ('UINT16', 'e_machine', { 'names' : { 3 : "Intel 80836" } }),
45
                        ('UINT32', 'e_version', {'format': "0x%x" }),
46
                        ('UINT32', 'e_entry', {'format': "0x%x" }),
47
                        ('UINT32', 'e_phoff', { 'format' : "%d (bytes into file)" }),
48
                        ('UINT32', 'e_shoff', { 'format' : "%d (bytes into file)" }),
49
                        ('UINT32', 'e_flags', {'format': "0x%x" }),
50
                        ('UINT16', 'e_ehsize', { 'format' : "%d (bytes)" } ),
51
                        ('UINT16', 'e_phentsize', { 'format' : "%d (bytes)" } ),
52
                        ('UINT16', 'e_phnum'),
53
                        ('UINT16', 'e_shentsize', { 'format' : "%d (bytes)" } ),
54
                        ('UINT16', 'e_shnum'),
55
                        ('UINT16', 'e_shstrndx')
56
                )
57
 
58
        def __str__(self):
59
                f = StringIO.StringIO()
60
                f.write("ELF Header:\n")
61
                for name, attr in [("Class", "ei_class"),
62
                                   ("Data", "ei_data"),
63
                                   ("Version", "ei_version"),
64
                                   ("OS/ABI", "ei_osabi"),
65
                                   ("ABI Version", "ei_abiversion"),
66
                                   ("Type", "e_type"),
67
                                   ("Machine", "e_machine"),
68
                                   ("Version", "e_version"),
69
                                   ("Entry point address", "e_entry"),
70
                                   ("Start of program headers", "e_phoff"),
71
                                   ("Start of section headers", "e_shoff"),
72
                                   ("Flags", "e_flags"),
73
                                   ("Size of this header", "e_ehsize"),
74
                                   ("Size of program headers", "e_phentsize"),
75
                                   ("Number of program headers", "e_phnum"),
76
                                   ("Size of section headers", "e_shentsize"),
77
                                   ("Number of section headers", "e_shnum"),
78
                                   ("Section header string table index", "e_shstrndx"),
79
                                   ]:
80
                        f.write("  %-35s%s\n" % ("%s:" % name, getattr(self.ai, attr)))
81
                return f.getvalue()
82
 
83
class Elf64Header(Elf32Header):
84
        # Inherit from Elf32Header to get the constants.
85
        def __init__(self):
86
                AIStruct.__init__(self, AIStruct.SIZE64)
87
                self.setup(
88
                        ('UINT8', 'ei_magic', {'times': 4}),
89
                        ('UINT8', 'ei_class'),
90
                        ('UINT8', 'ei_data'),
91
                        ('UINT8', 'ei_version'),
92
                        ('UINT8', 'ei_padding', {'times': 9}),
93
                        ('UINT16', 'e_type'),
94
                        ('UINT16', 'e_machine'),
95
                        ('UINT32', 'e_version'),
96
                        ('UINT64', 'e_entry'),
97
                        ('UINT64', 'e_phoff'),
98
                        ('UINT64', 'e_shoff'),
99
                        ('UINT32', 'e_flags'),
100
                        ('UINT16', 'e_ehsize'),
101
                        ('UINT16', 'e_phentsize'),
102
                        ('UINT16', 'e_phnum'),
103
                        ('UINT16', 'e_shentsize'),
104
                        ('UINT16', 'e_shnum'),
105
                        ('UINT16', 'e_shstrndx')
106
                )
107
 
108
class Elf32SectionHeader(AIStruct):
109
        SHF_WRITE = 1 << 0
110
        SHF_ALLOC = 1 << 1
111
        SHF_EXECINSTR = 1 << 2
112
 
113
        def __init__(self, *args, **kwargs):
114
                AIStruct.__init__(self, AIStruct.SIZE32)
115
                self.elffile = kwargs["elffile"]
116
                self.index = kwargs["index"]
117
 
118
                def format_flags(x):
119
                        if x == (self.SHF_WRITE | self.SHF_ALLOC):
120
                                return "WA"
121
                        if x == (self.SHF_EXECINSTR | self.SHF_ALLOC):
122
                                return "AX"
123
                        if x == self.SHF_WRITE:
124
                                return "W"
125
                        if x == self.SHF_ALLOC:
126
                                return "A"
127
                        if x == self.SHF_EXECINSTR:
128
                                return "X"
129
                        return "%x" % x
130
 
131
                self.mutated = 0
132
                self._name = None
133
 
134
                self.setup(
135
                        ('UINT32', 'sh_name', {"format" : self.elffile.get_name}),
136
                        ('UINT32', 'sh_type', {"names" : {0:"NULL", 1:"PROGBITS", 2:"SYMTAB", 3:"STRTAB", 8:"NOBITS"}}),
137
                        ('UINT32', 'sh_flags', {"format": format_flags}),
138
                        ('UINT32', 'sh_addr', {"format" : "%08x"}),
139
                        ('UINT32', 'sh_offset', {"format" : "%06x"}),
140
                        ('UINT32', 'sh_size', {"format" : "%06x"}),
141
                        ('UINT32', 'sh_link'),
142
                        ('UINT32', 'sh_info', {"format" : "%3d"}),
143
                        ('UINT32', 'sh_addralign', {"format" : "%2d"}),
144
                        ('UINT32', 'sh_entsize', {"format" : "%02x"}),
145
                )
146
 
147
        def get_name(self):
148
                if not self._name:
149
                        self._name = self.elffile.get_name(self.ai.sh_name)
150
                return self._name
151
 
152
        def set_name(self, value):
153
                self._name = value
154
        name = property(get_name, set_name)
155
 
156
        def get_sym_name(self, value):
157
                strtab =  ElfFileStringTable \
158
                         (self.elffile.gfile, self.elffile.sheaders[self.ai.sh_link.get()])
159
                return strtab.read(value)
160
 
161
 
162
        def allocable(self):
163
                return self.ai.sh_flags.get() & self.SHF_ALLOC
164
 
165
        def writable(self):
166
                return self.ai.sh_flags.get() & self.SHF_WRITE
167
 
168
        def executable(self):
169
                return self.ai.sh_flags.get() & self.SHF_EXECINSTR
170
 
171
        def get_perms(self):
172
                # Only call on allocatable
173
                assert self.allocable()
174
                rwx = (1 << 2);
175
                if self.writable():
176
                        rwx |= (1 << 1)
177
                if self.executable():
178
                        rwx |= 1
179
                return rwx
180
 
181
        def container(self, cls):
182
                size = cls(section = self).struct_size()
183
                return ElfFileContainer(self.elffile.gfile, AIStruct.SIZE32, self.ai.sh_offset.get(),
184
                               size, self.ai.sh_size.get() / size,
185
                               cls, section=self)
186
 
187
 
188
class Elf64SectionHeader(AIStruct):
189
        def __init__(self, *args, **kwargs):
190
                AIStruct.__init__(self, AIStruct.SIZE64)
191
                self.setup(
192
                        ('UINT32', 'sh_name'),
193
                        ('UINT32', 'sh_type'),
194
                        ('UINT64', 'sh_flags'),
195
                        ('UINT64', 'sh_addr'),
196
                        ('UINT64', 'sh_offset'),
197
                        ('UINT64', 'sh_size'),
198
                        ('UINT32', 'sh_link'),
199
                        ('UINT32', 'sh_info'),
200
                        ('UINT64', 'sh_addralign'),
201
                        ('UINT64', 'sh_entsize'),
202
                )
203
 
204
 
205
class Elf32ProgramHeader(AIStruct):
206
        PT_NULL = 0
207
        PT_NULL = 0
208
        PT_LOAD = 1
209
        PT_DYNAMIC = 2
210
        PT_INTERP = 3
211
        PT_NOTE = 4
212
        PT_SHLIB = 5
213
        PT_PHDR = 6
214
        PT_NUM = 7
215
        PT_LOOS = 0x60000000
216
        PT_HIOS = 0x6fffffff
217
        PT_LOPROC = 0x70000000
218
        PT_HIPROC = 0x7fffffff
219
 
220
        PF_X = 1 << 0
221
        PF_W = 1 << 1
222
        PF_R = 1 << 2
223
        PF_MASKPROC = 0xf0000000L
224
 
225
        def __init__(self, *args, **kwargs):
226
                AIStruct.__init__(self, AIStruct.SIZE32)
227
                self.elffile = kwargs["elffile"]
228
                def format_flags(x):
229
                        the_str = [' ', ' ', ' ']
230
                        if (x & self.PF_X):
231
                                the_str[2] = 'E'
232
                        if (x & self.PF_W):
233
                                the_str[1] = 'W'
234
                        if (x & self.PF_R):
235
                                the_str[0] = 'R'
236
                        return "".join(the_str)
237
 
238
                self.setup(
239
                        ('UINT32', 'p_type', {"names" :
240
                                              {0: "NULL",
241
                                               1: "LOAD",
242
                                               2 : "DYNAMIC",
243
                                               3 : "INTERP",
244
                                               4 : "NOTE",
245
                                               1685382481 : "GNU_STACK",
246
                                               1694766464 : "PAX_FLAGS",
247
                                               }
248
                                              }  ),
249
                        ('UINT32', 'p_offset', {"format": "0x%06x"}),
250
                        ('UINT32', 'p_vaddr', {"format": "0x%08x"}),
251
                        ('UINT32', 'p_paddr', {"format": "0x%08x"}),
252
                        ('UINT32', 'p_filesz', {"format": "0x%05x"}),
253
                        ('UINT32', 'p_memsz', {"format": "0x%05x"}),
254
                        ('UINT32', 'p_flags', {"format": format_flags}),
255
                        ('UINT32', 'p_align', {"format": "0x%x"}),
256
                )
257
 
258
class Elf64ProgramHeader(Elf32ProgramHeader):
259
        def __init__(self, *args, **kwargs):
260
                AIStruct.__init__(self, AIStruct.SIZE64)
261
                self.setup(
262
                        ('UINT32', 'p_type', {"names" : {0: "NULL", 1: "LOAD", 2 : "DYNAMIC", 3 : "INTERP", 4 : "NOTE"}}  ),
263
                        ('UINT32', 'p_flags'),
264
                        ('UINT64', 'p_offset'),
265
                        ('UINT64', 'p_vaddr'),
266
                        ('UINT64', 'p_paddr'),
267
                        ('UINT64', 'p_filesz'),
268
                        ('UINT64', 'p_memsz'),
269
                        ('UINT64', 'p_align'),
270
                )
271
 
272
class ElfFileException(Exception):
273
        pass
274
 
275
class ElfFileNotElfException(ElfFileException):
276
        pass
277
 
278
class ElfFileContainer(object):
279
        def __init__(self, gfile, word_size, offset, entsize, number, cls, **kwargs):
280
                self.gfile = gfile
281
                self.word_size = word_size
282
                self.offset = offset
283
                self.entsize = entsize
284
                self.number = number
285
                self.cls = cls
286
                self.mutated = 0
287
                self.container = []
288
                self.kwargs = kwargs
289
 
290
        def mutate(self):
291
                print "Making it mutable"
292
                for each in self:
293
                        self.container.append(each)
294
                self.mutated = 1
295
 
296
        def __delitem__(self, idx):
297
                if not self.mutated: self.mutate()
298
                self.container.__delitem__(idx)
299
 
300
        def __getitem__(self, idx):
301
                if type(idx) == type(""):
302
                        # Act like a dictionary
303
                        for each in self:
304
                                if str(each.ai.sh_name) == idx:
305
                                        return each
306
                        raise "badness"
307
                else:
308
                        if self.mutated:
309
                                print "mutated", idx, self.container
310
                                return self.container[idx]
311
                        else:
312
                                num = idx
313
                                assert num >= 0
314
                                if num >= self.number:
315
                                        raise StopIteration()
316
                                inst = self.cls(self.word_size, index=num, **self.kwargs)
317
                                poker = BitPoker.new_with_gfile(self.gfile, self.offset + (self.entsize * num))
318
                                inst.read_from_poker(poker)
319
                                return inst
320
 
321
        def __len__(self):
322
                return self.number
323
 
324
class ElfFileProgramHeaderContainer(ElfFileContainer):
325
        def __str__(self):
326
                f = StringIO.StringIO()
327
                f.write("Program Headers:\n")
328
                format_str = "  %-15s%-9s%-11s%-11s%-8s%-8s%-4s%s\n"
329
                f.write(format_str % ("Type", "Offset", "VirtAddr",
330
                                      "PhysAddr", "FileSiz", "MemSiz", "Flg", "Align"))
331
                for header in self:
332
                        x = header.ai
333
                        f.write(format_str % (x.p_type, x.p_offset, x.p_vaddr,
334
                                              x.p_paddr, x.p_filesz, x.p_memsz, x.p_flags, x.p_align))
335
                return f.getvalue()
336
 
337
class ElfFileSectionHeaderContainer(ElfFileContainer):
338
        def __str__(self):
339
                f = StringIO.StringIO()
340
                f.write("There are %d section headers, starting at offset 0x%x:\n\n" % (len(self), self.kwargs["elffile"].header.ai.e_shoff.get()))
341
                f.write("Section Headers:\n")
342
                format_str = "  [%2s] %-17.17s %-15s %-8s %-6s %-6s %2s %3s %2s %-3s %-2s\n"
343
                f.write(format_str % ("Nr", "Name", "Type", "Addr", "Off", "Size",
344
                                      "ES", "Flg", "Lk", "Inf", "Al"))
345
                for idx, header in enumerate(self):
346
                        x = header.ai
347
                        f.write(format_str % (idx, x.sh_name, x.sh_type, x.sh_addr,
348
                                              x.sh_offset, x.sh_size, x.sh_entsize,
349
                                              x.sh_flags, x.sh_link, x.sh_info,
350
                                              x.sh_addralign))
351
                return f.getvalue()
352
 
353
 
354
class ElfFileStringTable(object):
355
        def __init__(self, gfile, section_header):
356
                file_offset = section_header.ai.sh_offset
357
                self.poker = BitPoker.new_with_gfile(gfile, file_offset)
358
 
359
        def read(self, offset):
360
                return self.poker.read_c_string(offset)
361
 
362
 
363
class Symbols(AIStruct):
364
    def __init__(self, *args, **kwargs):
365
        AIStruct.__init__(self, AIStruct.SIZE32)
366
        self.section = kwargs["section"]
367
        self.setup(
368
            ('UINT32', 'st_name', {"format" : self.section.get_sym_name}),
369
            ('UINT32', 'value'),
370
            ('UINT32', 'size'),
371
            ('UINT8', 'info'),
372
            ('UINT8', 'other'),
373
            ('UINT16', 'st_shndx')
374
            )
375
 
376
    def __str__(self):
377
        return "[%s] 0x%08x %5d %3d" % \
378
               (self.ai.st_name, self.ai.value.get(),
379
                self.ai.size.get(), self.ai.st_shndx.get())
380
 
381
 
382
class ElfFileSymbolTable(object):
383
        def __init__(self, gfile, section_header):
384
                self.header = section_header
385
                file_offset = section_header.ai.sh_offset
386
                self.poker = BitPoker.new_with_gfile(gfile, file_offset)
387
 
388
        def get_symbols(self, section_num = None):
389
                if section_num:
390
                        return [ sym for sym in self.header.container(Symbols) if sym.ai.st_shndx.get() == section_num]
391
                else:
392
                        return self.header.container(Symbols)
393
 
394
class ElfFile(object):
395
        WORD_SIZE_MAP = {Elf32Header.EI_CLASS_32: Elf32Header.SIZE32,
396
                        Elf32Header.EI_CLASS_64: Elf32Header.SIZE64}
397
        BYTE_ORDER_MAP = {Elf32Header.EI_DATA_LSB: 'lsb',
398
                        Elf32Header.EI_DATA_MSB: 'msb'}
399
        HEADER_MAP = {Elf32Header.SIZE32: Elf32Header, Elf64Header.SIZE64: Elf64Header}
400
        PROGRAM_HEADER_MAP = {Elf32Header.SIZE32: Elf32ProgramHeader, Elf64Header.SIZE64: Elf64ProgramHeader}
401
        SECTION_HEADER_MAP = {Elf32Header.SIZE32: Elf32SectionHeader, Elf64Header.SIZE64: Elf64SectionHeader}
402
        """ Python representation of an Elf file. """
403
        def __init__(self, gfile, byte_ordering, word_size):
404
                self.gfile = gfile
405
                self.gfile.set_byte_ordering(byte_ordering)
406
                self.byte_order = byte_ordering
407
                self.word_size = word_size
408
 
409
                self.header = ElfFile.HEADER_MAP[self.word_size]()
410
                self.header.read_from_poker(BitPoker.new_with_gfile(self.gfile, 0))
411
                # Setup the parts of the file
412
                # ... program headers
413
                self.pheaders = ElfFileProgramHeaderContainer \
414
                                (gfile, word_size, self.header.ai.e_phoff, self.header.ai.e_phentsize,
415
                                self.header.ai.e_phnum.get(), ElfFile.PROGRAM_HEADER_MAP[word_size], elffile=self)
416
                # ... section headers
417
                self.sheaders = ElfFileSectionHeaderContainer \
418
                                (gfile, word_size, self.header.ai.e_shoff, self.header.ai.e_shentsize,
419
                                self.header.ai.e_shnum.get(), ElfFile.SECTION_HEADER_MAP[word_size], elffile=self)
420
                # ... string table
421
                if self.header.ai.e_shstrndx != 0:
422
                        self.string_table = ElfFileStringTable \
423
                                (self.gfile, self.sheaders[self.header.ai.e_shstrndx])
424
 
425
                # ... symbol table
426
                self.symtable = None
427
                for header in self.sheaders:
428
                        if header.get_name() == ".symtab":
429
                                self.symtable = ElfFileSymbolTable(self.gfile, header)
430
 
431
        def set_source(self, poker):
432
                self.source_poker = poker
433
 
434
        def get_name(self, idx):
435
                return self.string_table.read(idx)
436
 
437
        def print_info(self):
438
                print "* Information for ELF file:"
439
                print "* Header info:"
440
                self.header.print_info()
441
 
442
 
443
        def write_file(selfm, filename):
444
                # Write out head
445
                print "Wirintg out", filename
446
 
447
        def from_file(filename):
448
                gfile = GFile.existing(filename)
449
                poker = BitPoker()
450
                poker.set_mmapfile(gfile.mapping, 0) # Offset of 0 from start of file.
451
                poker.set_byte_ordering('lsb') # Use default because we don't (yet) know
452
                header = Elf32Header() # Once again, use a default size.
453
                header.read_from_poker(poker)
454
                # Examine the header for info we need.
455
                # Check the magic first. If we don't and the file is non-ELF, chances are
456
                # class & data won't match which will result in a confusing error message
457
                if header.ai.ei_magic != Elf32Header.EI_MAGIC:
458
                        raise ElfFileNotElfException("Wanted magic %r, got %r" \
459
                                        % (Elf32Header.EI_MAGIC, header.ai.ei_magic))
460
                word_size = ElfFile.WORD_SIZE_MAP[header.ai.ei_class.get()]
461
                byte_order = ElfFile.BYTE_ORDER_MAP[header.ai.ei_data.get()]
462
                return ElfFile(gfile, byte_order, word_size)
463
        from_file = staticmethod(from_file)
464
 
465
 
466
def test():
467
        "Test suite"
468
 
469
        elf_file = ElfFile.from_file("a.out")
470
 
471
        # Check can load an elf
472
        success = 1
473
        try:
474
            x = ElfFile.from_file("a.out")
475
        except:
476
            success = 0
477
        assert success
478
 
479
        # CHeck can't load not and elf
480
        success = 0
481
        try:
482
            x = ElfFile.from_file("pyelf.py")
483
        except:
484
            success = 1
485
 
486
        assert success
487
 
488
 
489
def main():
490
        filename = sys.argv[1] # Consider this a usage message :)
491
        elf_file = ElfFile.from_file(filename)
492
        elf_file.print_info()
493
 
494
if __name__ == '__main__':
495
        if sys.argv[1] != "test":
496
                main()
497
        else:
498
                test()
499
 
500
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.