File Coverage

blib/lib/Devel/PeekPoke.pm
Criterion Covered Total %
statement 52 54 96.3
branch 15 22 68.1
condition 7 11 63.6
subroutine 8 9 88.8
pod 4 4 100.0
total 86 100 86.0


line stmt bran cond sub pod time code
1             package Devel::PeekPoke;
2 3     3   62792 use strict;
  3         8  
  3         162  
3 3     3   19 use warnings;
  3         6  
  3         155  
4              
5             our $VERSION = '0.04';
6              
7 3     3   17 use Carp;
  3         23  
  3         322  
8 3     3   1838 use Devel::PeekPoke::Constants qw/PTR_SIZE PTR_PACK_TYPE BIG_ENDIAN/;
  3         8  
  3         595  
9              
10             if (
11             $ENV{DEVEL_PEEK_POKE_USE_PP}
12             or
13             # when someone writes the XS this should just work
14             ! eval { require XSLoader; XSLoader::load( __PACKAGE__, $VERSION ) }
15             ) {
16             require Devel::PeekPoke::PP;
17             *peek = \&Devel::PeekPoke::PP::peek;
18             *poke = \&Devel::PeekPoke::PP::poke;
19              
20             # sanity checks an address value before packing it
21             *_pack_address = \&Devel::PeekPoke::PP::_pack_address;
22             }
23              
24 3     3   20 use base 'Exporter';
  3         4  
  3         3004  
25             our @EXPORT = qw/peek poke/;
26             our @EXPORT_OK = qw/peek poke peek_address poke_address peek_verbose describe_bytestring/;
27              
28             =head1 NAME
29              
30             Devel::PeekPoke - All your bytes are belong to us
31              
32             =head1 DESCRIPTION
33              
34             This module provides a toolset for raw memory manipulation (both reading and
35             writing), together with some tools making it easier to examine memory chunks.
36              
37             All provided routines expect memory addresses as regular integers (not as their
38             packed representations). Note that you can only manipulate memory of your
39             current perl process, this is B a general memory access tool.
40              
41             =head1 PORTABILITY
42              
43             The implementation is very portable, and is expected to work on all
44             architectures and operating systems supported by perl itself. Moreover no
45             compiler toolchain is required to install this module (in fact currently no
46             XS version is available).
47              
48             In order to interpret the results, you may need to know the details of the
49             underlying system architecture. See L for some
50             useful constants related to the current system.
51              
52             =head1 USE RESPONSIBLY
53              
54             It is apparent with the least amount of imagination that this module can be
55             used for great evil and general mischief. On the other hand there are some
56             legitimate uses, if nothing else as a learning/debugging tool. Hence this
57             tool is provided ( L
58             |http://groups.google.com/group/alt.hackers/msg/8ce9ba2e5554e8e6>)
59             in the interest of free speech and all. The authors expect a user of this
60             module to exercise maximum common sense.
61              
62              
63             =head1 EXPORTABLE FUNCTIONS
64              
65             The following functions are provided, with L and L being
66             exported by default.
67              
68             =head2 peek
69              
70             my $byte_string = peek( $address, $size );
71              
72             Reads and returns C<$size> B from the supplied address. Expects
73             C<$address> to be specified as an integer.
74              
75             =head2 poke
76              
77             my $bytes_written = poke( $address, $bytes );
78              
79             Writes the contents of C<$bytes> to the memory location C<$address>. Returns
80             the amount of bytes written. Expects C<$bytes> to be a raw byte string, throws
81             an exception when (possible) characters are detected.
82              
83             =cut
84              
85             # peek and poke come either from Devel::PeekPoke::PP or the XS implementation
86              
87             =head2 peek_address
88              
89             my $address = peek_address( $pointer_address );
90              
91             A convenience function to retrieve an address from a known location of a
92             pointer. The address is returned as an integer. Equivalent to:
93              
94             unpack (
95             Devel::PeekPoke::Constants::PTR_PACK_TYPE,
96             peek( $pointer_address, Devel::PeekPoke::Constants::PTR_SIZE ),
97             )
98              
99             =cut
100              
101             sub peek_address {
102             #my($location) = @_;
103 1 50   1 1 5 croak "Peek address where?" unless defined $_[0];
104 1         5 unpack PTR_PACK_TYPE, peek($_[0], PTR_SIZE);
105             }
106              
107             =head2 poke_address
108              
109             my $addr_size = poke_address( $pointer_address, $address_value );
110              
111             A convenience function to set a pointer to an arbitrary address an address
112             (you need to ensure that C<$pointer_address> is in fact a pointer).
113             Equivalent to:
114              
115             poke( $pointer_address, pack (
116             Devel::PeekPoke::Constants::PTR_PACK_TYPE,
117             $address_value,
118             ));
119              
120             =cut
121              
122             sub poke_address {
123             #my($location, $addr) = @_;
124 2 50 33 2 1 41 croak "Poke address where and to what?"
125             unless (defined $_[0]) and (defined $_[1]);
126 2         8 poke( $_[0], _pack_address( $_[1]) );
127             }
128              
129             =head2 peek_verbose
130              
131             peek_verbose( $address, $size )
132              
133             A convenience wrapper around L. Equivalent to:
134              
135             print STDERR describe_bytestring( peek($address, $size), $address);
136              
137             =cut
138              
139             sub peek_verbose {
140             #my($location, $len) = @_;
141 0     0 1 0 my $out = describe_bytestring( peek(@_), $_[0]);
142              
143 0         0 print STDERR "$out\n";
144             }
145              
146             =head2 describe_bytestring
147              
148             my $desc = describe_bytestring( $bytes, $start_address )
149              
150             A convenience aid for examination of random bytestrings. Useful for those of
151             us who are not skilled enough to read hex dumps directly. For example:
152              
153             describe_bytestring( "Har har\t\x13\x37\xb0\x0b\x1e\x55 !!!", 46685601519 )
154              
155             returns the following on a little-endian system (regardless of pointer size):
156              
157             Hex Dec Oct Bin ASCII 32 32+2 64
158             -------------------------------- -------- -------- ----------------
159             0xadeadbeef 48 72 110 01001000 H 20726148 0972616820726148
160             0xadeadbef0 61 97 141 01100001 a ___/ _______/
161             0xadeadbef1 72 114 162 01110010 r __/ 61682072 ______/
162             0xadeadbef2 20 32 40 00100000 (SP) _/ ___/ _____/
163             0xadeadbef3 68 104 150 01101000 h 09726168 __/ ____/
164             0xadeadbef4 61 97 141 01100001 a ___/ _/ ___/
165             0xadeadbef5 72 114 162 01110010 r __/ 37130972 __/
166             0xadeadbef6 09 9 11 00001001 (HT) _/ ___/ _/
167             0xadeadbef7 13 19 23 00010011 (DC3) 0BB03713 __/ 2120551E0BB03713
168             0xadeadbef8 37 55 67 00110111 7 ___/ _/ _______/
169             0xadeadbef9 B0 176 260 10110000 "\260" __/ 551E0BB0 ______/
170             0xadeadbefa 0B 11 13 00001011 (VT) _/ ___/ _____/
171             0xadeadbefb 1E 30 36 00011110 (RS) 2120551E __/ ____/
172             0xadeadbefc 55 85 125 01010101 U ___/ _/ ___/
173             0xadeadbefd 20 32 40 00100000 (SP) __/ 21212120 __/
174             0xadeadbefe 21 33 41 00100001 ! _/ ___/ _/
175             0xadeadbeff 21 33 41 00100001 ! __/
176             0xadeadbf00 21 33 41 00100001 ! _/
177              
178             =cut
179              
180             # compile a list of short C0 code names (why doesn't charnames.pm provide me with this?)
181             my $ctrl_names;
182             for (qw/
183             NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US SP
184             /) {
185             $ctrl_names->{scalar keys %$ctrl_names} = $_;
186             };
187             $ctrl_names->{127} = 'DEL';
188             for (values %$ctrl_names) {
189             $_ = "($_)" . ( ' ' x (4 - length $_) );
190             }
191              
192             sub describe_bytestring {
193 1     1 1 9 my ($bytes, $start_addr) = @_;
194              
195 1         681 require Devel::PeekPoke::BigInt;
196 1   50     29 $start_addr = Devel::PeekPoke::BigInt->new($start_addr || 0);
197              
198 1         33953 my $len = length($bytes);
199              
200 1         5 my $max_addr_hexsize = length ( ($start_addr + $len)->as_unmarked_hex );
201 1 50       147 $max_addr_hexsize = 7 if $max_addr_hexsize < 7; # to match perl itself (minimum 7 digits)
202 1         5 my $addr_hdr_pad = ' ' x ($max_addr_hexsize + 3);
203              
204 1         5 my @out = (
205             "$addr_hdr_pad Hex Dec Oct Bin ASCII ",
206             "$addr_hdr_pad-------------------------------- ",
207             );
208              
209 1 50       5 if ($len > 3) {
210 1         4 $out[0] .= ' 32 ';
211 1         3 $out[1] .= ' --------';
212             }
213              
214 1 50       4 if ($len > 5) {
215 1         3 $out[0] .= ' 32+2 ';
216 1         2 $out[1] .= ' --------';
217             }
218              
219 1 50       5 if ($len > 7) {
220 1         4 $out[0] .= ' 64 ';
221 1         3 $out[1] .= ' ----------------';
222             }
223              
224 1         4 for my $off (0 .. $len - 1) {
225 18         29 my $byte = substr $bytes, $off, 1;
226 18         34 my ($val) = unpack ('C', $byte);
227 18   66     96 push @out, sprintf( "0x%0${max_addr_hexsize}s %02X % 4d % 4o %s %s",
228             ($start_addr + $off)->as_unmarked_hex,
229             ($val) x 3,
230             unpack('B8', $byte),
231             $ctrl_names->{$val} || ( $val > 127 ? sprintf('"\%o"', $val) : " $byte " ),
232             );
233              
234 18         1691 my @ints;
235 18         32 for my $col_32 (0,2) {
236 36         49 my $start_off_32 = ($off - $col_32) % 4;
237              
238 36 100 100     145 if ( ($off < $col_32) or ($len - $off + $start_off_32) < 4 ) {
239 4         12 push @ints, (' ' x 8);
240             }
241             else {
242 32 100       147 push @ints,
243             $start_off_32 == 0 ? sprintf '%08X', unpack('L', substr $bytes, $off - $start_off_32, 4)
244             : sprintf '%s/%s', '_' x (4 - $start_off_32), ' ' x ($start_off_32 + 3)
245             ;
246             }
247             }
248              
249             # print as two successive 32bit values, based on the determined endianness
250             # since the machine may very well not have unpack('Q',...)
251 18         31 my $start_off_64 = $off % 8;
252 18 100       38 if ( ($len - $off + $start_off_64) >= 8) {
253 16 100       59 push @ints,
254             $start_off_64 == 0 ? sprintf '%08X%08X', unpack('LL', BIG_ENDIAN
255             ? substr( $bytes, $off, 8 )
256             : substr( $bytes, $off + 4, 4 ) . substr( $bytes, $off, 4 )
257             )
258             : sprintf '%s/%s', '_' x (8 - $start_off_64), ' ' x ($start_off_64 + 7)
259             ;
260             }
261              
262 18 50       96 $out[-1] .= join ' ', ' ', @ints
263             if @ints;
264             }
265              
266 1         77 s/\s+$// for @out;
267 1         18 join "\n", @out, '';
268             }
269              
270             =head1 AUTHOR
271              
272             ribasushi: Peter Rabbitson
273              
274             =head1 CONTRIBUTORS
275              
276             None as of yet
277              
278             =head1 COPYRIGHT
279              
280             Copyright (c) 2011 the Devel::PeekPoke L and L
281             as listed above.
282              
283             =head1 LICENSE
284              
285             This library is free software and may be distributed under the same terms
286             as perl itself.
287              
288             =cut
289              
290             1;