Version 4 of ELF

Updated 2012-09-10 14:32:17 by LkpPo

A common platform-independent binary format for object files, libraries and executables, widely used on UNIX systems.


AMG: Here's code to dump the contents of an ELF file, by section. At present, it only supports 32-bit little-endian ELF, since I don't have any other kind of ELF file on hand to check it against. It uses code adapted from Dump a file in hex and ASCII. There are many section attributes and other headers it could print, but doesn't; it's easy to add support for what you need. It might not work on stripped binaries.

Reference: [L1 ]

#!/usr/bin/env tclsh

if {[llength $argv] == 0 || [llength $argv] > 2} {
    puts stderr "Usage: [file tail $argv0] FILENAME ?PATTERN?"
    puts stderr "FILENAME: Name of a 32-bit LE ELF file to dump"
    puts stderr "PATTERN: Glob-style section name match pattern"
    puts stderr "All section names are printed if PATTERN is omitted"
    exit 1
}

proc hex {data} {
    set result ""
    for {set i 0} {$i < [string length $data]} {incr i 16} {
        set row [string range $data $i [expr {$i + 15}]]
        binary scan $row H* hex
        set hex [regsub -all {(.{4})} [format %-32s $hex] {\1 }]
        set row [regsub -all {[^[:print:]]} $row .]
        append result [format "%08x: %s %-16s\n" $i $hex $row]
    }
    string range $result 0 end-1
}

proc unsigned {bits args} {
    foreach varname $args {
        upvar 1 $varname var
        set var [expr {$var & ((1 << $bits) - 1)}]
    }
}

proc sections {chan} {
    seek $chan 32
    binary scan [read $chan 4] i shoff
    unsigned 32 shoff

    seek $chan 46
    binary scan [read $chan 12] sss shentsize shnum shstrndx
    unsigned 16 shentsize shnum shstrndx

    seek $chan [expr {$shoff + 16 + $shstrndx * $shentsize}]
    binary scan [read $chan 8] ii strtaboff strtabsize
    unsigned 32 strtaboff strtabsize

    seek $chan $strtaboff
    set strtab [read $chan $strtabsize]

    seek $chan $shoff
    set result {}
    for {set i 0} {$i < $shnum} {incr i} {
        binary scan [read $chan $shentsize] ix12ii name offset size
        unsigned 32 name offset size

        if {[string index $strtab $name] ne "\0"} {
            set end [expr {[string first \0 $strtab $name] - 1}]
            lappend result [string range $strtab $name $end] $offset $size
        }
    }
    return $result
}

proc dumpsections {filename {pattern ""}} {
    set chan [open $filename rb]
    if {[read $chan 7] ne "\177ELF\1\1\1"} {
        error "unsupported format"
    }
    foreach {name offset size} [sections $chan] {
        if {$pattern eq ""} {
            puts [format "%-32s %08x %08x" $name $offset $size]
        } elseif {[string match $pattern $name]} {
            seek $chan $offset
            puts [format "%-32s %08x %08x" $name $offset $size]
            puts [hex [read $chan $size]]
        }
    }
    close $chan
}

dumpsections [lindex $argv 0] [lindex $argv 1]

Example:

[andy@toaster|~/dwarf]$ ./dumpsections.tcl test.o
.text                            00000034 0000001c
.rel.text                        00001688 00000018
.data                            00000050 00000000
.bss                             00000050 00000000
.debug_abbrev                    00000050 000000d9
.debug_info                      00000129 00000160
.rel.debug_info                  000016a0 000000a8
.debug_line                      00000289 0000003a
.rel.debug_line                  00001748 00000008
.debug_macinfo                   000002c3 00000cd7
.debug_loc                       00000f9a 0000002c
.debug_pubnames                  00000fc6 0000002b
.rel.debug_pubnames              00001750 00000008
.debug_aranges                   00000ff1 00000020
.rel.debug_aranges               00001758 00000010
.debug_str                       00001011 0000005c
.comment                         0000106d 00000012
.note.GNU-stack                  0000107f 00000000
.debug_frame                     00001080 0000002c
.rel.debug_frame                 00001768 00000010
.shstrtab                        000010ac 000000d4
.symtab                          00001540 00000130
.strtab                          00001670 00000015
[andy@toaster|~/dwarf]$ ./dumpsections.tcl test.o .debug_str
.debug_str                       00001011 0000005c
00000000: 756e 7369 676e 6564 2069 6e74 006c 6f6e  unsigned int.lon
00000010: 676e 616d 6500 6c6f 6e67 2069 6e74 0061  gname.long int.a
00000020: 7267 7600 6172 6763 006d 6169 6e00 6368  rgv.argc.main.ch
00000030: 6172 006e 6578 7400 2f68 6f6d 652f 616e  ar.next./home/an
00000040: 6479 2f64 7761 7266 0074 6573 742e 6300  dy/dwarf.test.c.
00000050: 474e 5520 4320 342e 342e 3400            GNU C 4.4.4.