#!/usr/bin/perl 

# jkob 13/04/2007  14/12/2011  30/11/201 


sub usage {

    print <<EOF;

NAZWA
   $name -- układ pamięci dla danego procesu

SKŁADNIA
   $name [-u k|K|m|M|g|G|t|T|p|P] [-x] <command name>
   
OPIS PROGRAMU 
    Program wywołuje pmap dla PID odpowiadającego podanej komendzie i wypisuje adresy w
    systemie dziesiętnym zamiast szestnastkowym. Adresy mogą być wypisywane w KB, MB, GB,
    itd. (dokładniej KiB, MiB, ...).


OPCJE PROGRAMU
   -u k|K adresy w KiB (adres/2^10)
  
   -u m|M adresy w MiB (adres/2^20)

   -u g|G adresy w GiB (adres/2^30)

   -u t|T adresy w TiB (adres/2^40)

   -u p|P adresy w PiB (adres/2^50)

   -u e|E adresy w EiB (adres/2^60)

   -u z|Z adresy w ZiB (adres/2^70)


DODATKOWE INFORMACJE

   Zob. Jonathan Corbet (lwn.net, November 15, 2017) 

   Since the beginning, Linux has mapped the kernel's memory into the address space of
   every running process. There are solid performance reasons for doing this, and the
   processor's memory-management unit can ordinarily be trusted to prevent user space from
   accessing that memory. More recently, though, some more subtle security issues related
   to this mapping have come to light, leading to the rapid development of a new patch set
   that ends this longstanding practice for the x86 architecture.


   On 32-bit systems, the address-space layout for a running process dedicated the bottom
   3GB (0x00000000 to 0xbfffffff) for user-space use and the top 1GB (0xc0000000 to
   0xffffffff) for the kernel. Each process saw its own memory in the bottom 3GB, while
   the kernel-space mapping was the same for all. On an x86_64 system, the user-space
   virtual address space goes from zero to 0x7fffffffffff (the bottom 47 bits), while
   kernel-space mappings are scattered in the range above 0xffff880000000000. While user
   space can, in some sense, see the address space reserved for the kernel, it has no
   actual access to that memory.  

   This mapping scheme has caused problems in the past. On 32-bit systems, it limits the
   total size of a process's address space to 3GB, for example. The kernel-side problems
   are arguably worse, in that the kernel can only directly access a bit less than 1GB of
   physical memory; using more memory than that required the implementation of a
   complicated "high memory" mechanism. 32-Bit systems were never going to be great at
   using large amounts of memory (for a 20th-century value of "large"), but keeping the
   kernel mapped into user space made things worse.



AUTOR 
   Jacek Kobus (jkob\@fizyka.umk.pl)
  
EOF
}

$name=`basename $0`;
chop($name);

use Getopt::Std;
getopts('hdpu:xX');

if ($opt_h) {
    usage();
}

if (! defined $ARGV[0]) {
    usage();
    exit;
} 

$command=shift;

if ( $command =~ '^\d+$' ) {
    $pid=$command;
} else {
    $pid=`pgrep "$command" | tail -1`;
}

sub prtf {

    my $num=shift;
    my $unit=shift;
    my $format="%16.4f";

    if ( $unit =~ /[kK]/ ) {
	$usymb="K";
	$factor=2**10;
    }

    if ( $unit =~ /[mM]/ ) {
	$usymb="M";
	$factor=2**20;
    }

    if ( $unit =~ /[gG]/ ) {
	$usymb="G";
	$factor=2**30;
    }

    if ( $unit =~ /[tT]/ ) {
	$usymb="T";
	$factor=2**40;
    }

    if ( $unit =~ /[pP]/ ) {
	$usymb="P";
	$factor=2**50;
    }

    if ( $unit =~ /[eE]/ ) {
	$usymb="P";
	$factor=2**60;
    }

    if ( $unit =~ /[zZ]/ ) {
	$usymb="Z";
	$factor=2**70;
    }

    printf "$format $usymb",$num/$factor;
}

sub hex2dec {

    my $hex=shift;
    my @hextab=split('',$hex);
    my $dec=0;
    my $power=1;
    for (my $i=$#hextab; $i>=0; $i--) {
#	print $i,": ",$hextab[$i],"\n";
	$hextab[$i] =~ s/a/10/i;
	$hextab[$i] =~ s/b/11/i;
	$hextab[$i] =~ s/c/12/i;
	$hextab[$i] =~ s/d/13/i;
	$hextab[$i] =~ s/e/14/i;
	$hextab[$i] =~ s/f/15/i;
	$dec=$dec+$hextab[$i]*$power;
	$power=$power*16;
    }

    my $format="%20.0f";
    if (defined($opt_u)) {
	prtf ($dec,$opt_u);
    } else {
	printf "$format ",$dec;
    }
}

#`pmap $pid`;

if (defined($opt_x)) {
    open (PMAP,"pmap -x $pid|") or die $!,"\n";
} elsif (defined($opt_d)) {
    open (PMAP,"pmap -d $pid|") or die $!,"\n";
} elsif (defined($opt_p)) {
    open (PMAP,"pmap -p $pid|") or die $!,"\n";
} elsif (defined($opt_X)) {
    open (PMAP,"pmap -X $pid|") or die $!,"\n";
} else {
    open (PMAP,"pmap  $pid|") or die $!,"\n";
}

my @pmap=<PMAP>;

for (my $line=1; $line<=$#pmap; $line++) {
#    print $pmap[$line];
    if ( $pmap[$line] =~ /total/ ) {
	print $pmap[$line];
	next;
    }

    if ( $pmap[$line] =~ /Address/ ) {
	print "    ",$pmap[$line];
	next;
    }

    if ( $pmap[$line] =~ /$pid:/ ) {
	print $pmap[$line];
	next;
    }

    $pmap[$line] =~ /([01-9abcdef]+)\s(.*)/i;
    $address=$1;
    $therest=$2;
    hex2dec($address);print "  ",$therest,"\n";
}

close(PMAP);
