File Coverage

blib/lib/Parse/Readelf.pm
Criterion Covered Total %
statement 56 56 100.0
branch 29 30 96.6
condition 9 12 75.0
subroutine 8 8 100.0
pod 2 2 100.0
total 104 108 96.3


line stmt bran cond sub pod time code
1             package Parse::Readelf;
2              
3             # Author, Copyright and License: see end of file
4              
5             =head1 NAME
6              
7             Parse::Readelf - handle readelf's output with a class
8              
9             =head1 SYNOPSIS
10              
11             use Parse::Readelf;
12              
13             my $readelf_data = new Parse::Readelf($executable);
14             $readelf_data->print_structure_layout($re_identifier, 1);
15              
16             =head1 ABSTRACT
17              
18             Parse::Readelf parses (some of) the output of C and stores
19             its interesting details in some objects to ease access.
20              
21             At the moment only a very limited access to the structure layout of
22             data types and variables is supported.
23              
24             =head1 DESCRIPTION
25              
26             Normally an object of this class is constructed with the file name of
27             an object file to be parsed. Upon construction the file is analysed
28             and all relevant information about its debug info section is stored
29             inside of the object or one of its subobjects. This information can
30             be accessed afterwards using a bunch of getter methods, see
31             L for details.
32              
33             This is BETA software, use at your own risk.
34              
35             At the moment only information regarding the binary arrangement of
36             variables (Structure Layout) is supported (and that is regularly used
37             at my company, so the worst bugs should by found by now). Other data
38             is ignored for now.
39              
40             Currently only output for B is supported.
41             Please contact the author for other versions and provide some example
42             C outputs.
43              
44             =cut
45              
46             #########################################################################
47              
48 2     2   6607 use 5.006001;
  2         7  
49 2     2   8 use strict;
  2         4  
  2         32  
50 2     2   8 use warnings;
  2         3  
  2         38  
51 2     2   8 use Carp;
  2         3  
  2         128  
52              
53             our $VERSION = '0.19';
54              
55 2     2   851 use Parse::Readelf::Debug::Line;
  2         4  
  2         78  
56 2     2   1022 use Parse::Readelf::Debug::Info ':constants';
  2         4  
  2         1614  
57              
58             #########################################################################
59              
60             =head1 EXPORT
61              
62             Nothing is exported by default as it's normally not needed to modify
63             the following variable:
64              
65             This module exports nothing directly, it should be accessed via its
66             methods only.
67              
68             =cut
69              
70             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
71              
72             require Exporter;
73              
74             our @ISA = qw(Exporter);
75             our @EXPORT = qw();
76             our %EXPORT_TAGS = ( 'all' => [ qw(@structure_layout_types) ] );
77             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
78              
79             #########################################################################
80              
81             =head2 I<@structure_layout_types>
82              
83             is a list of the types that can be printed in a structure layout. Its
84             elements are basically the tag identifieres from C's output
85             without the prefix B.
86              
87             =cut
88              
89             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
90              
91             our @structure_layout_types = qw(class
92             enumerat
93             member
94             structure
95             subrange
96             typedef
97             union
98             variable);
99              
100             #########################################################################
101              
102             =head2 new - get readelf's output into an object
103              
104             $readelf_data = new Parse::Readelf($file_name);
105              
106             =head3 example:
107              
108             $readelf_data1 = new Parse::Readelf('program');
109             $readelf_data2 = new Parse::Readelf('module.o');
110              
111             =head3 parameters:
112              
113             $file_name name of executable or object file
114              
115             =head3 description:
116              
117             This method parses the output of several C commands and
118             stores its interesting details internally to be accessed later by
119             getter methods described below.
120              
121             =head3 returns:
122              
123             The method returns the blessed Parse::Readelf object or an
124             exception in case of an error.
125              
126             =cut
127              
128             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
129             sub new($$)
130             {
131 6     6 1 41440 my $this = shift;
132 6   100     42 my $class = ref($this) || $this;
133 6         13 my ($file_name) = @_;
134 6         19 my %self = (line_info => undef,
135             debug_info => undef);
136 6         11 local $_;
137              
138             # checks:
139 6 100       25 if (! $file_name)
140 1         138 { croak 'bad call to new of ', __PACKAGE__ }
141 5 100       14 if (ref($this))
142 1         275 { carp 'cloning of a ', __PACKAGE__, ' object is not supported' }
143 5 100       178 if (! -f $file_name)
144 1         116 { croak __PACKAGE__, " can't find ", $file_name }
145              
146             # parse all supported readelf sections:
147 4         43 $self{line_info} = new Parse::Readelf::Debug::Line($file_name);
148             $self{debug_info} =
149 4         124 new Parse::Readelf::Debug::Info($file_name, $self{line_info});
150              
151             # last consistency check:
152             confess 'incomplete constructed object in ', __PACKAGE__
153 4 50 33     42 unless defined $self{line_info} and defined $self{debug_info};
154              
155 4         6664 bless \%self, $class;
156             }
157              
158             #########################################################################
159              
160             =head2 print_structure_layout - print structure layout of variables/types
161              
162             $readelf_data->print_structure_layout($re_name [, $print_location]);
163              
164             =head3 example:
165              
166             $readelf_data->print_structure_layout('_t$');
167             $readelf_data->print_structure_layout('_t$', 1);
168              
169             =head3 parameters:
170              
171             $re_name reg. exp. matching name of variable or data type
172             $print_location optional flag to print location with every definition
173              
174             =head3 description:
175              
176             This method prints the structure layout of one or more variables
177             or data types that match the regular expression for their name.
178             If the optional parameter $print_location is true, each line also
179             contains source location information, if availablble.
180              
181             =head3 returns:
182              
183             nothing
184              
185             =cut
186              
187             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
188             sub print_structure_layout($$;$)
189             {
190 9     9 1 33695 my $this = shift;
191 9         24 my ($re_name, $print_location) = @_;
192 9         15 local $_;
193              
194             # get item IDs for all matching items:
195             my @ids =
196             $this->{debug_info}
197 9         93 ->item_ids_matching($re_name,
198             '^DW_TAG_(?:'.
199             join('|', @structure_layout_types).
200             ')'
201             );
202              
203             # get layout for each item
204 9         17 my @layouts = ();
205 9         17 foreach (@ids)
206 20         73 { push @layouts, $this->{debug_info}->structure_layout($_) }
207              
208             # get maximum width for each field:
209 9         19 my ($level_name_width, $offset_width, $bit_offset_width, $type_width) =
210             (1, 1, 0, 1);
211 9         16 foreach (@layouts)
212             {
213 118         150 my $width = length($_->[$NAME]) + 2 * $_->[$LEVEL];
214 118 100       153 $level_name_width = $width if $level_name_width < $width;
215 118 100       179 $offset_width = length($_->[$OFFSET])
216             if $offset_width < length($_->[$OFFSET]);
217 118 100 100     194 $bit_offset_width = length($_->[$BITOFFSET]) + 1
218             if defined $_->[$BITOFFSET] and
219             $bit_offset_width < length($_->[$BITOFFSET]) + 1;
220 118 100       173 $width = $_->[$TYPE] ne '' ? length($_->[$TYPE]) + 3 : 2;
221 118         126 $width += length($_->[$SIZE]);
222 118 100       158 $width += length(defined $_->[$BITSIZE]) + 4 if defined $_->[$BITSIZE];
223 118 100       174 $type_width = $width if $width > $type_width;
224             }
225              
226             # now print items:
227 9 100       309 printf("%s %-*s %-*s %s\n",
228             substr('OFFSET ', 0 , $offset_width + $bit_offset_width),
229             $level_name_width, 'STRUCTURE',
230             $type_width, 'TYPE (SIZE)',
231             ($print_location ? 'SOURCE LOCATION' : ''));
232 9         45 foreach (@layouts)
233             {
234 118 100       507 my $type_size = sprintf("%s(%s%d)",
    100          
235             ($_->[$TYPE] ne '' ? $_->[$TYPE].' ' : ''),
236             (defined $_->[$BITSIZE]
237             ? $_->[$BITSIZE].' in ' : ''),
238             $_->[$SIZE]);
239 118         135 my $location = '';
240 118 100 66     214 if ($print_location and defined $_->[$LOCATION])
241             {
242             $location =
243 8         45 $this->{line_info}->file($_->[$LOCATION]->[0],
244             $_->[$LOCATION]->[1],
245             1)
246             . ':' . $_->[$LOCATION]->[2];
247             }
248 118 100       1396 printf("%0*d%-*s %-*s %-*s %s\n",
249             $offset_width, $_->[$OFFSET],
250             $bit_offset_width, (defined $_->[$BITOFFSET]
251             ? '.'.$_->[$BITOFFSET] : ''),
252             $level_name_width, (' ' x $_->[$LEVEL]) . $_->[$NAME],
253             $type_width, $type_size,
254             $location);
255             }
256             }
257              
258             1;
259              
260             #########################################################################
261              
262             __END__