File Coverage

examples/elf.pl
Criterion Covered Total %
statement 24 106 22.6
branch 2 52 3.8
condition 0 15 0.0
subroutine 6 12 50.0
pod n/a
total 32 185 17.3


line stmt bran cond sub pod time code
1             #!/usr/local/pkg/cover/20070318/sw/bin/perl -w
2             ################################################################################
3             #
4             # $Project: /Convert-Binary-C $
5             # $Author: mhx $
6             # $Date: 2006/02/10 06:56:36 +0100 $
7             # $Revision: 2 $
8             # $Source: /bin/elf.PL $
9             #
10             ################################################################################
11             #
12             # Copyright (c) 2005-2006 Marcus Holland-Moritz. All rights reserved.
13             # This program is free software; you can redistribute it and/or modify
14             # it under the same terms as Perl itself.
15             #
16             ################################################################################
17              
18 1     1   33 use Convert::Binary::C;
  1         10  
  1         14  
19 1     1   41 use Data::Dumper;
  1         10  
  1         22  
20 1     1   38 use Getopt::Long;
  1         9  
  1         20  
21 1     1   16 use strict;
  1         9  
  1         25  
22              
23             #-------------------------------------------------
24             # Constants for accessing ELF identification data
25             #-------------------------------------------------
26 1     1   14 use constant EI_CLASS => 4;
  1         9  
  1         15  
27 1     1   14 use constant EI_DATA => 5;
  1         47  
  1         13  
28              
29 1         12 my %opt;
30 1         27 Getopt::Long::Configure('bundling');
31 1 50       74 unless (GetOptions(\%opt, qw( list|l info|i debug section|s=s symbols ))) {
32 0         0   eval q{
33             require Pod::Usage;
34             Pod::Usage::pod2usage(2);
35             };
36 0         0   print "Cannot show help, please consider installing Pod::Usage.\n";
37 0         0   exit;
38             }
39              
40 1 50       842 unless (@ARGV) {
41 1         79   print "No input file (try '$0 -h' for usage).\n";
42 1         16   exit;
43             }
44              
45             #---------------------------------------------------
46             # Compiler Configuration (generated using ccconfig)
47             #---------------------------------------------------
48 0         0 my %config = (
49               Alignment => 4,
50               CharSize => 1,
51               CompoundAlignment => 1,
52               IntSize => 4,
53               LongLongSize => 8,
54               LongSize => 4,
55               ShortSize => 2,
56               UnsignedChars => 0
57             );
58              
59             #-----------
60             # ELF Types
61             #-----------
62 0         0 my @elftype = qw( ET_NONE ET_REL ET_EXEC ET_DYN ET_CORE );
63              
64             #-------------------
65             # ELF Section Types
66             #-------------------
67 0         0 my @sectype = qw(
68             SHT_NULL SHT_PROGBITS SHT_SYMTAB SHT_STRTAB SHT_RELA SHT_HASH
69             SHT_DYNAMIC SHT_NOTE SHT_NOBITS SHT_REL SHT_SHLIB SHT_DYNSYM
70             );
71              
72             #-------------------
73             # ELF Machine Types
74             #-------------------
75 0         0 my %machine = (
76                0 => 'EM_NONE (No machine)',
77                1 => 'EM_M32 (AT&T WE 32100)',
78                2 => 'EM_SPARC (SUN SPARC)',
79                3 => 'EM_386 (Intel 80386)',
80                4 => 'EM_68K (Motorola m68k family)',
81                5 => 'EM_88K (Motorola m88k family)',
82                7 => 'EM_860 (Intel 80860)',
83                8 => 'EM_MIPS (MIPS R3000 big-endian)',
84                9 => 'EM_S370 (IBM System/370)',
85               10 => 'EM_MIPS_RS3_LE (MIPS R3000 little-endian)',
86               15 => 'EM_PARISC (HPPA)',
87               17 => 'EM_VPP500 (Fujitsu VPP500)',
88               18 => 'EM_SPARC32PLUS (Sun\'s "v8plus")',
89               19 => 'EM_960 (Intel 80960)',
90               20 => 'EM_PPC (PowerPC)',
91               21 => 'EM_PPC64 (PowerPC 64-bit)',
92               22 => 'EM_S390 (IBM S390)',
93               36 => 'EM_V800 (NEC V800 series)',
94               37 => 'EM_FR20 (Fujitsu FR20)',
95               38 => 'EM_RH32 (TRW RH-32)',
96               39 => 'EM_RCE (Motorola RCE)',
97               40 => 'EM_ARM (ARM)',
98               41 => 'EM_FAKE_ALPHA (Digital Alpha)',
99               42 => 'EM_SH (Hitachi SH)',
100               43 => 'EM_SPARCV9 (SPARC v9 64-bit)',
101               44 => 'EM_TRICORE (Siemens Tricore)',
102               45 => 'EM_ARC (Argonaut RISC Core)',
103               46 => 'EM_H8_300 (Hitachi H8/300)',
104               47 => 'EM_H8_300H (Hitachi H8/300H)',
105               48 => 'EM_H8S (Hitachi H8S)',
106               49 => 'EM_H8_500 (Hitachi H8/500)',
107               50 => 'EM_IA_64 (Intel Merced)',
108               51 => 'EM_MIPS_X (Stanford MIPS-X)',
109               52 => 'EM_COLDFIRE (Motorola Coldfire)',
110               53 => 'EM_68HC12 (Motorola M68HC12)',
111               54 => 'EM_MMA (Fujitsu MMA Multimedia Accelerator)',
112               55 => 'EM_PCP (Siemens PCP)',
113               56 => 'EM_NCPU (Sony nCPU embeeded RISC)',
114               57 => 'EM_NDR1 (Denso NDR1 microprocessor)',
115               58 => 'EM_STARCORE (Motorola Start*Core processor)',
116               59 => 'EM_ME16 (Toyota ME16 processor)',
117               60 => 'EM_ST100 (STMicroelectronic ST100 processor)',
118               61 => 'EM_TINYJ (Advanced Logic Corp. Tinyj emb.fam)',
119               62 => 'EM_X86_64 (AMD x86-64 architecture)',
120               63 => 'EM_PDSP (Sony DSP Processor)',
121               66 => 'EM_FX66 (Siemens FX66 microcontroller)',
122               67 => 'EM_ST9PLUS (STMicroelectronics ST9+ 8/16 mc)',
123               68 => 'EM_ST7 (STmicroelectronics ST7 8 bit mc)',
124               69 => 'EM_68HC16 (Motorola MC68HC16 microcontroller)',
125               70 => 'EM_68HC11 (Motorola MC68HC11 microcontroller)',
126               71 => 'EM_68HC08 (Motorola MC68HC08 microcontroller)',
127               72 => 'EM_68HC05 (Motorola MC68HC05 microcontroller)',
128               73 => 'EM_SVX (Silicon Graphics SVx)',
129               74 => 'EM_ST19 (STMicroelectronics ST19 8 bit mc)',
130               75 => 'EM_VAX (Digital VAX)',
131               76 => 'EM_CRIS (Axis Communications 32-bit embedded processor)',
132               77 => 'EM_JAVELIN (Infineon Technologies 32-bit embedded processor)',
133               78 => 'EM_FIREPATH (Element 14 64-bit DSP Processor)',
134               79 => 'EM_ZSP (LSI Logic 16-bit DSP Processor)',
135               80 => 'EM_MMIX (Donald Knuth\'s educational 64-bit processor)',
136               81 => 'EM_HUANY (Harvard University machine-independent object files)',
137               82 => 'EM_PRISM (SiTera Prism)',
138               83 => 'EM_AVR (Atmel AVR 8-bit microcontroller)',
139               84 => 'EM_FR30 (Fujitsu FR30)',
140               85 => 'EM_D10V (Mitsubishi D10V)',
141               86 => 'EM_D30V (Mitsubishi D30V)',
142               87 => 'EM_V850 (NEC v850)',
143               88 => 'EM_M32R (Mitsubishi M32R)',
144               89 => 'EM_MN10300 (Matsushita MN10300)',
145               90 => 'EM_MN10200 (Matsushita MN10200)',
146               91 => 'EM_PJ (picoJava)',
147               92 => 'EM_OPENRISC (OpenRISC 32-bit embedded processor)',
148               93 => 'EM_ARC_A5 (ARC Cores Tangent-A5)',
149               94 => 'EM_XTENSA (Tensilica Xtensa Architecture)',
150             );
151              
152             #-----------------------------
153             # ELF Symbol Binding and Type
154             #-----------------------------
155 0         0 my %symbind = (
156                0 => 'STB_LOCAL',
157                1 => 'STB_GLOBAL',
158                2 => 'STB_WEAK',
159                3 => 'STB_NUM',
160               10 => 'STB_LOOS',
161               12 => 'STB_HIOS',
162               13 => 'STB_LOPROC',
163               15 => 'STB_HIPROC',
164             );
165              
166 0         0 my %symtype = (
167                0 => 'STT_NOTYPE',
168                1 => 'STT_OBJECT',
169                2 => 'STT_FUNC',
170                3 => 'STT_SECTION',
171                4 => 'STT_FILE',
172                5 => 'STT_COMMON',
173                6 => 'STT_TLS',
174                7 => 'STT_NUM',
175               10 => 'STT_LOOS',
176               12 => 'STT_HIOS',
177               13 => 'STT_LOPROC',
178               15 => 'STT_HIPROC',
179             );
180              
181             #--------------------------------------------------------
182             # Create a C::B::C object to convert ELF data structures
183             #--------------------------------------------------------
184 0         0 my $ep = Convert::Binary::C->new(%config)->parse(elf_header());
185              
186             #-------------------------------------------
187             # Attach hooks to certain interesting types
188             #-------------------------------------------
189 0         0 my %hook = (
190               'Ehdr.e_machine' => \%machine,
191               'Ehdr.e_type' => \@elftype,
192               'Shdr.sh_type' => \@sectype,
193             );
194              
195 0         0 for my $c (qw( Elf32 Elf64 )) {
196 0         0   while (my($k,$v) = each %hook) {
197                 $ep->tag("$c\_$k", Hooks => { unpack => sub {
198 0 0   0   0       my $x = shift; (ref $v eq 'HASH' ? $v->{$x} : $v->[$x]) || "Unknown ($x)"
  0 0       0  
199 0         0     }});
200               }
201              
202               $ep->tag("$c\_Sym.st_info", Hooks => { unpack => sub {
203 0     0   0     my $x = shift;
204 0         0     my $b = $x >> 4;
205 0         0     my $t = $x & 0xf;
206                 {
207 0   0     0       sti_bind => $symbind{$b} || "Unknown ($b)",
      0        
208                   sti_type => $symtype{$t} || "Unknown ($t)",
209                 }
210 0         0   }});
211             }
212              
213             #---------------------------------------
214             # Read the whole ELF file (inefficient)
215             #---------------------------------------
216 0         0 my $elf = do { local($/, *FH);
  0         0  
217 0 0       0                open FH, $ARGV[0] or die "$ARGV[0]: $!\n";
218 0         0                <FH>;
219                          };
220              
221             #---------------------------------
222             # Process ELF identification data
223             #---------------------------------
224 0         0 my @ident = unpack "C16", substr $elf, 0, 16;
225              
226             #-----------------------------
227             # Is this really an ELF file?
228             #-----------------------------
229 0 0 0     0 unless ($ident[0] == 0x7F && pack("C*", @ident[1..3]) eq 'ELF')
230 0         0   { die "not an ELF file\n" }
231              
232             #-----------------------------
233             # Check ELF class (32/64-Bit)
234             #-----------------------------
235 0 0       0 if ($ident[EI_CLASS] == 0) { die "invalid ELF class ($ident[EI_CLASS])\n" }
  0         0  
236 0 0       0 if ($ident[EI_CLASS] > 2) { die "unsupported ELF class ($ident[EI_CLASS])\n" }
  0         0  
237 0 0       0 my $class = $ident[EI_CLASS] == 1 ? 'Elf32' : 'Elf64';
238              
239             #-------------------------------------------
240             # Check Byte Order (BigEndian/LittleEndian)
241             #-------------------------------------------
242 0 0       0 if ($ident[EI_DATA] == 0) { die "invalid data encoding ($ident[EI_DATA])\n" }
  0         0  
243 0 0       0 if ($ident[EI_DATA] > 2) { die "unsupported data encoding ($ident[EI_DATA])\n" }
  0         0  
244 0 0       0 $ep->ByteOrder($ident[EI_DATA] == 1 ? 'LittleEndian' : 'BigEndian');
245              
246             sub get
247             {
248 0     0       my($type, $off, $len) = @_;
249 0 0           $ep->unpack("$class\_$type", @_ > 2 ? substr $elf, $off, $len
250                                                   : substr $elf, $off);
251             }
252              
253             #---------------------------------------------------
254             # Unpack ELF header and section header string table
255             #---------------------------------------------------
256 0         0 my $header = get('Ehdr', 0);
257 0         0 my $shstrtab = get('Shdr', $header->{e_shoff} +
258                                        $header->{e_shstrndx}*$header->{e_shentsize});
259              
260 0 0       0 print Data::Dumper->Dump([$header], ["*$class\_Ehdr"]) if $opt{debug};
261              
262             #----------------------------
263             # Get Name from String Table
264             #----------------------------
265             sub get_name
266             {
267 0     0       my($tab, $off) = @_;
268 0             return unpack "Z*", substr $elf, $tab->{sh_offset} + $off;
269             }
270              
271             #--------------------------
272             # Read all section headers
273             #--------------------------
274 0         0 my %section; # for lookup by section name
275 0         0 my @section; # for lookup by section index
276              
277 0         0 for my $ix (0 .. $header->{e_shnum}-1) {
278 0         0   my $shdr = get('Shdr', $header->{e_shoff} + $ix*$header->{e_shentsize});
279 0 0       0   print Data::Dumper->Dump([$shdr], ["*$class\_Shdr"]) if $opt{debug};
280 0         0   $section{get_name($shstrtab, $shdr->{sh_name})} = $shdr;
281 0         0   push @section, $shdr;
282             }
283              
284             #-----------------------------------
285             # Get Section Name by Section Index
286             #-----------------------------------
287             sub get_section_name
288             {
289 0     0       my $sec = shift;
290 0 0 0         if ($sec == 0 || $sec >= 0xff00) {
291 0               my %res = (0 => 'SHN_UNDEF', 0xfff1 => 'SHN_ABS', 0xfff2 => 'SHN_COMMON');
292 0   0           return $res{$sec} || sprintf "reserved section 0x%04X", $sec;
293               }
294 0 0           return $sec < @section ? get_name($shstrtab, $section[$sec]{sh_name})
295                                      : "invalid section $sec";
296             }
297              
298             #--------------------------
299             # Print Header Information
300             #--------------------------
301 0 0       0 if ($opt{info}) {
302 0         0   printf "Byte Order: %s\n", $ep->ByteOrder;
303 0         0   printf "ELF Class : %s\n", $class;
304 0         0   printf "ELF Type : %s\n", $header->{e_type};
305 0         0   printf "Machine : %s\n", $header->{e_machine};
306             }
307              
308             #------------------------
309             # Print List Of Sections
310             #------------------------
311 0 0       0 if ($opt{list}) {
312 0         0   printf "%-3s %-38s %-13s %-9s %-9s\n%s\n",
313                      'Idx', 'Section', 'Type', 'Offset', 'Size', '-'x80;
314 0         0   for my $ix (0 .. $#section) {
315 0         0     my $sh = $section[$ix];
316 0         0     printf "%3d %-38s %-13s %9d %9d\n",
317                         $ix,
318                              get_name($shstrtab, $sh->{sh_name}),
319                                     $sh->{sh_type},
320                                            $sh->{sh_offset},
321                                                 $sh->{sh_size};
322               }
323             }
324              
325             #--------------------
326             # Print Symbol Table
327             #--------------------
328 0 0       0 if ($opt{symbols}) {
329 0 0       0   my $symtab = $section{'.symtab'} or die "got no symbol table\n";
330 0 0       0   my $strtab = $section{'.strtab'} or die "got no symbol string table\n";
331              
332 0         0   my @sym = get('Sym', $symtab->{sh_offset},