1 package Linux
::Proc
::Maps
;
2 # ABSTRACT: Read and write /proc/[pid]/maps files
3 # KEYWORDS: linux proc procfs
9 our $VERSION = '999.999'; # VERSION
12 use Exporter
qw(import);
13 use namespace
::clean
-except
=> [qw(import)];
15 our @EXPORT_OK = qw(read_maps write_maps parse_maps_single_line format_maps_single_line);
19 use Linux::Proc::Maps qw(read_maps);
22 my $vm_regions = read_maps(pid => $$);
24 # by pid with explicit procfs mount:
25 my $vm_regions = read_maps(mnt => '/proc', pid => 123);
28 my $vm_regions = read_maps(file => '/proc/456/maps');
32 This module reads and writes F</proc/[pid]/maps> files that contain listed mapped memory regions.
36 Read and parse a maps file, returning an arrayref of regions (each represented as a hashref). See
37 L</parse_maps_single_line> to see the format of the hashrefs.
39 my $regions = read_maps(%args);
44 * C<file> - Path to maps file
45 * C<pid> - Process ID (one of C<file> or C<pid> is required)
46 * C<mnt> - Absolute path where L<proc(5)> is mounted (optional, default: C</proc>)
51 my %args = @_ == 1 ? (pid
=> $_[0]) : @_;
53 my $file = $args{file
};
55 if (!$file and my $pid = $args{pid
}) {
56 if ($pid =~ /^\d+$/) {
57 require File
::Spec
::Functions
;
58 my $procfs = $args{mnt
} || $ENV{PERL_LINUX_PROC_MAPS_MOUNT
} ||
59 File
::Spec
::Functions
::catdir
(File
::Spec
::Functions
::rootdir
(), 'proc');
60 $file = File
::Spec
::Functions
::catfile
($procfs, $pid, 'maps');
67 $file or croak
'Filename or PID required';
68 open(my $fh, '<:encoding(UTF-8)', $file) or croak
"Open failed ($file): $!";
72 while (my $line = <$fh>) {
75 my $region = parse_maps_single_line
($line);
78 push @regions, $region;
86 Returns a string with the contents of a maps file from the memory regions passed
.
88 my $file_content = write_maps
(\
@regions, %args);
90 This
is the opposite of L
</read_maps
>.
95 * C<fh> - Write maps to this open file handle (optional)
96 * C<file> - Open this filepath and write maps to that file (optional)
101 my $regions = shift or croak
'Regions required';
104 ref $regions eq 'ARRAY' or croak
'Regions must be an arrayref';
108 for my $region (@$regions) {
109 $out .= format_maps_single_line
($region);
112 # maybe print out the memory regions to a filehandle
114 if (!$fh and my $file = $args{file
}) {
115 open($fh, '>:encoding(UTF-8)', $file) or croak
"Open failed ($file): $!";
117 print $fh $out if $fh;
122 =func parse_maps_single_line
124 Parse
and return a single line from a maps file into a region represented as a hashref
.
126 my $region = parse_maps_single_line
($line);
130 # address perms offset dev inode pathname
131 08048000-08056000 r-xp
00000000 03:0c
64593 /usr/sbin
/gpm
136 address_start
=> 134512640,
137 address_end
=> 134569984,
145 pathname
=> '/usr/sbin/gpm',
150 sub parse_maps_single_line
{
151 my $line = shift or croak
'Line from a maps file required';
155 my ($addr1, $addr2, $read, $write, $exec, $shared, $offset, $device, $inode, $pathname) = $line =~ m
{
157 ([[:xdigit
:]]+)-([[:xdigit
:]]+)
158 \s
+ ([r-
])([w-
])([x-
])([sp
])
160 \s
+ ([[:xdigit
:]]+:[[:xdigit
:]]+)
167 no warnings
'portable'; # for hex() on 64-bit perls
170 address_start
=> hex($addr1),
171 address_end
=> hex($addr2),
172 read => 'r' eq $read,
173 write => 'w' eq $write,
174 execute
=> 'x' eq $exec,
175 shared
=> 's' eq $shared,
176 offset
=> hex($offset),
179 pathname
=> $pathname || '',
183 =func format_maps_single_line
185 Return a single line
for a maps file from a region represented as a hashref
.
187 my $line = format_maps_single_line
(\
%region);
189 This
is the opposite of L
</parse_maps_single_line
>.
193 sub format_maps_single_line
{
194 my $region = shift or croak
'Region required';
196 my @args = @{$region}{qw(address_start address_end read write execute shared offset device inode)};
197 $args[2] = $args[2] ? 'r' : '-';
198 $args[3] = $args[3] ? 'w' : '-';
199 $args[4] = $args[4] ? 'x' : '-';
200 $args[5] = $args[5] ? 's' : 'p';
202 return sprintf("%-72s %s\n", sprintf("%x-%x %s%s%s%s %08x %s %d", @args), $region->{pathname
});
207 L<proc(5)> describes the file format.
211 Integer overloading may occur if you try to parse memory regions from address spaces larger than
212 your current architecture (or perl) supports. This is currently not fatal, though you will get
213 warnings from perl that you probably shouldn't ignore.