2009-05-15 21:45:51 +02:00
|
|
|
--- pmap.1
|
2010-03-05 02:05:40 +01:00
|
|
|
+++ pmap.1 2009-05-11 12:14:59.377902682 +0200
|
2009-05-15 21:45:51 +02:00
|
|
|
@@ -1,39 +1,60 @@
|
2006-12-19 00:17:32 +01:00
|
|
|
-'\" t
|
|
|
|
-.\" (The preceding line is a note to broken versions of man to tell
|
|
|
|
-.\" them to pre-process this man page with tbl)
|
|
|
|
-.\" Man page for pmap.
|
|
|
|
-.\" Licensed under version 2 of the GNU General Public License.
|
|
|
|
-.\" Written by Albert Cahalan.
|
|
|
|
+.\" pmap.1 - manpage for the pmap(1) utility, part of procps
|
|
|
|
.\"
|
|
|
|
-.TH PMAP 1 "October 26, 2002" "Linux" "Linux User's Manual"
|
|
|
|
+.\" Copyright (C) 2005 Robert Love
|
|
|
|
+.\" Licensed under the terms of the GNU General Public License, v2
|
|
|
|
+.TH PMAP 1 "12 Oct 2005" "Linux" "Linux User's Manual"
|
|
|
|
.SH NAME
|
|
|
|
-pmap \- report memory map of a process
|
|
|
|
+pmap \- display information about process memory mappings
|
|
|
|
|
|
|
|
.SH SYNOPSIS
|
|
|
|
-.nf
|
|
|
|
-pmap [ -x | -d ] [ -q ] pids...
|
|
|
|
-pmap -V
|
|
|
|
-.fi
|
2009-05-15 21:45:51 +02:00
|
|
|
+.BI "pmap [ \-d | \-q | \-h | \-V | \-A\ low,high ] " pid
|
2006-12-19 00:17:32 +01:00
|
|
|
|
|
|
|
.SH DESCRIPTION
|
|
|
|
-The pmap command reports the memory map of a process or processes.
|
|
|
|
-
|
|
|
|
-.SH "GENERAL OPTIONS"
|
|
|
|
-.TS
|
|
|
|
-l l l.
|
|
|
|
--x extended Show the extended format.
|
|
|
|
--d device Show the device format.
|
|
|
|
--q quiet Do not display some header/footer lines.
|
|
|
|
--V show version Displays version of program.
|
|
|
|
-.TE
|
|
|
|
+.BR pmap (1)
|
|
|
|
+displays information about a process's memory mappings, such as its stack,
|
|
|
|
+data segment, mapped files, and so on.
|
|
|
|
+.P
|
|
|
|
+The
|
|
|
|
+.BR pmap (1)
|
|
|
|
+utility will show, for each mapping of a given process, the starting byte
|
|
|
|
+address in the process's address space, the size, the RSS (size of the mapping
|
|
|
|
+in physical memory), the amount of dirty pages, the permission, the device node,
|
|
|
|
+the offset, and the file backing the mapping, if any.
|
|
|
|
+.P
|
|
|
|
+As the last line of output, the
|
|
|
|
+.BR pmap (1)
|
|
|
|
+utility will tally up the total size of all mappings as well as show the
|
|
|
|
+total size of writable/private mappings and of shared mappings.
|
|
|
|
+
|
|
|
|
+.SH OPTIONS
|
|
|
|
+.TP
|
|
|
|
+.B\-d, \-\^\-device
|
|
|
|
+Display major and minor device numbers.
|
|
|
|
+.TP
|
2009-05-15 21:45:51 +02:00
|
|
|
+.B\-A, \-\-limit=low,high
|
|
|
|
+Limit results to the given range.
|
|
|
|
+.TP
|
2006-12-19 00:17:32 +01:00
|
|
|
+.B\-q, \-\^\-quiet
|
|
|
|
+Hide header and memory statistics.
|
|
|
|
+.TP
|
|
|
|
+.B\-h, \-\^\-help
|
|
|
|
+Show pmap usage.
|
|
|
|
+.TP
|
|
|
|
+.B\-V, \-\^\-version
|
|
|
|
+Display version information.
|
|
|
|
+
|
|
|
|
+.SH FILES
|
|
|
|
+.IR /proc/pid/maps " and
|
|
|
|
+.IR /proc/pid/smaps " \-\- memory mapping information"
|
|
|
|
|
|
|
|
.SH "SEE ALSO"
|
|
|
|
-ps(1) pgrep(1)
|
|
|
|
+.BR ps (1),
|
|
|
|
+.BR top (1),
|
|
|
|
+.BR free (1),
|
|
|
|
+.BR vmstat (1)
|
|
|
|
|
|
|
|
-.SH STANDARDS
|
|
|
|
-No standards apply, but pmap looks an awful lot like a SunOS command.
|
|
|
|
+.SH AUTHORS
|
|
|
|
+Written by Chris Rivera.
|
|
|
|
|
|
|
|
-.SH AUTHOR
|
|
|
|
-Albert Cahalan <albert@users.sf.net> wrote pmap in 2002, and is the current
|
|
|
|
-maintainer of the procps collection. Please send bug reports
|
|
|
|
-to <procps-feedback@lists.sf.net>.
|
|
|
|
+The procps package is maintained by Albert Calahan. Please send
|
|
|
|
+bug reports to <albert@users.sf.net>.
|
2009-05-15 21:45:51 +02:00
|
|
|
--- pmap.c
|
2010-03-05 02:05:40 +01:00
|
|
|
+++ pmap.c 2009-06-16 16:28:36.169902773 +0200
|
|
|
|
@@ -1,372 +1,405 @@
|
2006-12-19 00:17:32 +01:00
|
|
|
/*
|
|
|
|
- * Copyright 2002 by Albert Cahalan; all rights reserved.
|
|
|
|
- * This file may be used subject to the terms and conditions of the
|
|
|
|
- * GNU Library General Public License Version 2, or any later version
|
|
|
|
- * at your option, as published by the Free Software Foundation.
|
|
|
|
- * This program is distributed in the hope that it will be useful,
|
|
|
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
- * GNU Library General Public License for more details.
|
|
|
|
+ * pmap - print the address space map of a process
|
|
|
|
+ *
|
|
|
|
+ * Chris Rivera <chrismrivera@gmail.com>
|
|
|
|
+ * Robert Love <rml@novell.com>
|
2009-05-15 21:45:51 +02:00
|
|
|
+ * Werner Fink <werner@suse.de>
|
2006-12-19 00:17:32 +01:00
|
|
|
+ *
|
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
|
+ * it under the terms of the GNU General Public License, v2, as
|
|
|
|
+ * published by the Free Software Foundation
|
|
|
|
+ *
|
|
|
|
+ * Copyright (C) 2003, 2005 Chris Rivera
|
2009-05-15 21:45:51 +02:00
|
|
|
+ * Copyright (C) 2009 Werner Fink
|
2006-12-19 00:17:32 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2009-05-15 21:45:51 +02:00
|
|
|
+#include <stdint.h>
|
2006-12-19 00:17:32 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
-#include <ctype.h>
|
|
|
|
-#include <sys/types.h>
|
|
|
|
-#include <sys/stat.h>
|
|
|
|
-#include <fcntl.h>
|
|
|
|
#include <string.h>
|
|
|
|
+#include <errno.h>
|
|
|
|
+#include <getopt.h>
|
2009-05-15 21:45:51 +02:00
|
|
|
+#include <sys/utsname.h>
|
|
|
|
#include <unistd.h>
|
2006-12-19 00:17:32 +01:00
|
|
|
|
2009-05-15 21:45:51 +02:00
|
|
|
-#include <sys/ipc.h>
|
|
|
|
-#include <sys/shm.h>
|
|
|
|
-
|
2006-12-19 00:17:32 +01:00
|
|
|
#include "proc/readproc.h"
|
|
|
|
#include "proc/version.h"
|
|
|
|
-#include "proc/escape.h"
|
|
|
|
-
|
|
|
|
-static void usage(void) NORETURN;
|
|
|
|
-static void usage(void){
|
|
|
|
- fprintf(stderr,
|
2009-05-15 21:45:51 +02:00
|
|
|
- "Usage: pmap [-x | -d] [-q] [-A low,high] pid...\n"
|
2006-12-19 00:17:32 +01:00
|
|
|
- "-x show details\n"
|
|
|
|
- "-d show offset and device number\n"
|
|
|
|
- "-q quiet; less header/footer info\n"
|
|
|
|
- "-V show the version number\n"
|
2009-05-15 21:45:51 +02:00
|
|
|
- "-A limit results to the given range\n"
|
2006-12-19 00:17:32 +01:00
|
|
|
- );
|
|
|
|
- exit(1);
|
|
|
|
-}
|
|
|
|
-
|
2009-05-15 21:45:51 +02:00
|
|
|
-
|
|
|
|
-static unsigned KLONG range_low;
|
|
|
|
-static unsigned KLONG range_high = ~0ull;
|
2006-12-19 00:17:32 +01:00
|
|
|
|
|
|
|
-static int V_option;
|
|
|
|
-static int r_option; // ignored -- for SunOS compatibility
|
|
|
|
-static int x_option;
|
|
|
|
-static int d_option;
|
|
|
|
-static int q_option;
|
|
|
|
-
|
|
|
|
-static unsigned shm_minor = ~0u;
|
|
|
|
-
|
|
|
|
-static void discover_shm_minor(void){
|
|
|
|
- void *addr;
|
|
|
|
- int shmid;
|
|
|
|
- char mapbuf[256];
|
|
|
|
-
|
|
|
|
- if(!freopen("/proc/self/maps", "r", stdin)) return;
|
|
|
|
-
|
|
|
|
- // create
|
|
|
|
- shmid = shmget(IPC_PRIVATE, 42, IPC_CREAT | 0666);
|
|
|
|
- if(shmid==-1) return; // failed; oh well
|
|
|
|
- // attach
|
|
|
|
- addr = shmat(shmid, NULL, SHM_RDONLY);
|
|
|
|
- if(addr==(void*)-1) goto out_destroy;
|
|
|
|
-
|
|
|
|
- while(fgets(mapbuf, sizeof mapbuf, stdin)){
|
|
|
|
- char flags[32];
|
|
|
|
- char *tmp; // to clean up unprintables
|
|
|
|
- unsigned KLONG start, end;
|
|
|
|
- unsigned long long file_offset, inode;
|
|
|
|
- unsigned dev_major, dev_minor;
|
|
|
|
- sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx %x:%x %Lu", &start, &end, flags, &file_offset, &dev_major, &dev_minor, &inode);
|
|
|
|
- tmp = strchr(mapbuf,'\n');
|
|
|
|
- if(tmp) *tmp='\0';
|
|
|
|
- tmp = mapbuf;
|
|
|
|
- while(*tmp){
|
|
|
|
- if(!isprint(*tmp)) *tmp='?';
|
|
|
|
- tmp++;
|
|
|
|
- }
|
|
|
|
- if(start > (unsigned long)addr) continue;
|
|
|
|
- if(dev_major) continue;
|
|
|
|
- if(flags[3] != 's') continue;
|
|
|
|
- if(strstr(mapbuf,"/SYSV")){
|
|
|
|
- shm_minor = dev_minor;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
+#define BUFFERSIZE 4096
|
2009-05-15 21:45:51 +02:00
|
|
|
+#define OBJECTSIZE 1024
|
2006-12-19 00:17:32 +01:00
|
|
|
|
|
|
|
- if(shmdt(addr)) perror("shmdt");
|
2010-03-05 02:05:40 +01:00
|
|
|
-
|
|
|
|
-out_destroy:
|
|
|
|
- if(shmctl(shmid, IPC_RMID, NULL)) perror("IPC_RMID");
|
2006-12-19 00:17:32 +01:00
|
|
|
+struct smap {
|
|
|
|
+ unsigned long size;
|
|
|
|
+ unsigned long rss;
|
2009-05-15 21:45:51 +02:00
|
|
|
+ unsigned long pss;
|
2006-12-19 00:17:32 +01:00
|
|
|
+ unsigned long shared_clean;
|
|
|
|
+ unsigned long shared_dirty;
|
|
|
|
+ unsigned long private_clean;
|
|
|
|
+ unsigned long private_dirty;
|
2009-05-15 21:45:51 +02:00
|
|
|
+ unsigned long referenced;
|
|
|
|
+ unsigned long swap;
|
2006-12-19 00:17:32 +01:00
|
|
|
+};
|
|
|
|
+
|
2009-05-15 21:45:51 +02:00
|
|
|
+static unsigned long long range_low;
|
|
|
|
+static unsigned long long range_high = ~0ULL;
|
2006-12-19 00:17:32 +01:00
|
|
|
+static unsigned long mapped;
|
|
|
|
+static unsigned long shared;
|
|
|
|
+static unsigned long private;
|
|
|
|
+static unsigned long rss;
|
2009-05-15 21:45:51 +02:00
|
|
|
+static unsigned long pss;
|
2006-12-19 00:17:32 +01:00
|
|
|
+static unsigned long dirty;
|
2009-05-15 21:45:51 +02:00
|
|
|
+static unsigned long referenced;
|
|
|
|
+static unsigned long swap;
|
2006-12-19 00:17:32 +01:00
|
|
|
+static FILE *smaps_fp;
|
2009-06-19 23:35:26 +02:00
|
|
|
+static int maj, min, patch, dopss, noref, doswap, dopage;
|
2009-05-15 21:45:51 +02:00
|
|
|
+static long lbits;
|
|
|
|
+#define BLK ((lbits==64)?" ":"")
|
|
|
|
+#define WDT ((lbits==64)?16:8)
|
2006-12-19 00:17:32 +01:00
|
|
|
+
|
|
|
|
+static void usage(const char *cmd)
|
|
|
|
+{
|
|
|
|
+ fprintf(stderr, "usage: %s [options] pid\n", cmd);
|
|
|
|
+ fprintf(stderr, " -d, --device "
|
|
|
|
+ "display offset and device numbers\n");
|
|
|
|
+ fprintf(stderr, " -q, --quiet "
|
|
|
|
+ "hide header and memory statistics\n");
|
2009-05-15 21:45:51 +02:00
|
|
|
+ fprintf(stderr, " -A, --limit=low,high "
|
|
|
|
+ "limit results to the given range\n");
|
2006-12-19 00:17:32 +01:00
|
|
|
+ fprintf(stderr, " -V, --version "
|
|
|
|
+ "display version information\n");
|
|
|
|
+ fprintf(stderr, " -h, --help "
|
|
|
|
+ "display this help\n");
|
|
|
|
+}
|
|
|
|
|
2010-03-05 02:05:40 +01:00
|
|
|
- return;
|
2006-12-19 00:17:32 +01:00
|
|
|
+static int get_smap_data(struct smap *smap)
|
|
|
|
+{
|
|
|
|
+ unsigned long long data;
|
|
|
|
+ int assigned;
|
|
|
|
+ char buff[BUFFERSIZE];
|
|
|
|
+
|
|
|
|
+ /* get main line */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE - 1, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "%llx-", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ /* get size */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Size: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->size = data;
|
|
|
|
+
|
|
|
|
+ /* get rss */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Rss: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->rss = data;
|
|
|
|
+ rss += data;
|
|
|
|
+
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (dopss) {
|
|
|
|
+ /* get pss */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Pss: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->pss = data;
|
|
|
|
+ pss += data;
|
|
|
|
+ }
|
|
|
|
+
|
2006-12-19 00:17:32 +01:00
|
|
|
+ /* get shared clean */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Shared_Clean: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->shared_clean = data;
|
|
|
|
+
|
|
|
|
+ /* get shared dirty */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Shared_Dirty: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->shared_dirty = data;
|
|
|
|
+ dirty += data;
|
|
|
|
+
|
|
|
|
+ /* get private clean */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Private_Clean: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->private_clean = data;
|
|
|
|
+
|
|
|
|
+ /* get private dirty */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Private_Dirty: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->private_dirty = data;
|
|
|
|
+ dirty += data;
|
2009-05-15 21:45:51 +02:00
|
|
|
+
|
|
|
|
+ if (noref)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ /* get referenced */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Referenced: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->referenced = data;
|
|
|
|
+ referenced += data;
|
|
|
|
+
|
|
|
|
+ if (!doswap)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ /* get swap */
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(buff, "Swap: %lld", &data);
|
|
|
|
+ if (assigned != 1)
|
|
|
|
+ return 1;
|
|
|
|
+ smap->swap = data;
|
|
|
|
+ swap += data;
|
2009-06-19 23:35:26 +02:00
|
|
|
+
|
|
|
|
+ if (!dopage)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
|
|
|
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
|
|
|
|
+ return 1;
|
2009-05-15 21:45:51 +02:00
|
|
|
+out:
|
2006-12-19 00:17:32 +01:00
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static void parse_line(pid_t pid, const char *line, int show_devices)
|
|
|
|
+{
|
|
|
|
+ unsigned long long low, high, size, offset;
|
|
|
|
+ unsigned long major, minor;
|
2009-05-15 21:45:51 +02:00
|
|
|
+ struct smap smap = { .rss = 0, .pss = 0 };
|
2006-12-19 00:17:32 +01:00
|
|
|
+ int assigned;
|
|
|
|
+ char read_perm, write_perm, exec_perm, access_type;
|
|
|
|
+ char obj_buff[OBJECTSIZE] = "[anon]";
|
|
|
|
+
|
|
|
|
+ assigned = sscanf(line, "%llx-%llx %c%c%c%c %llx %lx:%lx %*u %"
|
|
|
|
+ STRINGIFY(OBJECTSIZE) "s", &low, &high, &read_perm,
|
|
|
|
+ &write_perm, &exec_perm, &access_type, &offset, &major,
|
|
|
|
+ &minor, obj_buff);
|
|
|
|
+
|
|
|
|
+ if (assigned < 9) {
|
|
|
|
+ fprintf(stderr, "failed to parse /proc/%d/maps\n", pid);
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ size = high - low;
|
|
|
|
+ size /= 1024;
|
|
|
|
+ mapped += size;
|
|
|
|
+
|
|
|
|
+ if (smaps_fp && get_smap_data(&smap)) {
|
|
|
|
+ fprintf(stderr, "failed to parse /proc/%d/smaps\n", pid);
|
|
|
|
+ exit(1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (access_type == 's')
|
|
|
|
+ shared += size;
|
|
|
|
+ else if (access_type == 'p' && write_perm == 'w')
|
|
|
|
+ private += size;
|
|
|
|
+
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if(low > range_high)
|
|
|
|
+ return;
|
|
|
|
+ if(high < range_low)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ printf("%0*llx %6lluK ", WDT, low, size);
|
2006-12-19 00:17:32 +01:00
|
|
|
+
|
|
|
|
+ if (smaps_fp) {
|
|
|
|
+ printf("%6luK ", smap.rss);
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (dopss)
|
|
|
|
+ printf("%6luK ", smap.pss);
|
2006-12-19 00:17:32 +01:00
|
|
|
+ printf("%6luK ", smap.private_dirty + smap.shared_dirty);
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (doswap)
|
|
|
|
+ printf("%6luK ", smap.swap);
|
2006-12-19 00:17:32 +01:00
|
|
|
+ }
|
|
|
|
|
|
|
|
-static const char *mapping_name(proc_t *p, unsigned KLONG addr, unsigned KLONG len, const char *mapbuf, unsigned showpath, unsigned dev_major, unsigned dev_minor, unsigned long long inode){
|
|
|
|
- const char *cp;
|
2010-03-05 02:05:40 +01:00
|
|
|
+ printf("%c%c%c%c ", read_perm, write_perm, exec_perm, access_type);
|
|
|
|
|
2006-12-19 00:17:32 +01:00
|
|
|
- if(!dev_major && dev_minor==shm_minor && strstr(mapbuf,"/SYSV")){
|
|
|
|
- static char shmbuf[64];
|
|
|
|
- snprintf(shmbuf, sizeof shmbuf, " [ shmid=0x%Lx ]", inode);
|
|
|
|
- return shmbuf;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- cp = strrchr(mapbuf,'/');
|
|
|
|
- if(cp){
|
|
|
|
- if(showpath) return strchr(mapbuf,'/');
|
|
|
|
- return cp[1] ? cp+1 : cp;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- cp = strchr(mapbuf,'/');
|
|
|
|
- if(cp){
|
|
|
|
- if(showpath) return cp;
|
|
|
|
- return strrchr(cp,'/') + 1; // it WILL succeed
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- cp = " [ anon ]";
|
|
|
|
- if( (p->start_stack >= addr) && (p->start_stack <= addr+len) ) cp = " [ stack ]";
|
|
|
|
- return cp;
|
|
|
|
-}
|
2010-03-05 02:05:40 +01:00
|
|
|
+ if (show_devices)
|
|
|
|
+ printf("%0*llx %02lx:%02lx ", WDT, offset, major, minor);
|
2006-12-19 00:17:32 +01:00
|
|
|
|
|
|
|
-static int one_proc(proc_t *p){
|
|
|
|
- char buf[32];
|
|
|
|
- char mapbuf[9600];
|
|
|
|
- char cmdbuf[512];
|
|
|
|
- unsigned long total_shared = 0ul;
|
|
|
|
- unsigned long total_private_readonly = 0ul;
|
|
|
|
- unsigned long total_private_writeable = 0ul;
|
|
|
|
-
|
|
|
|
- // Overkill, but who knows what is proper? The "w" prog
|
|
|
|
- // uses the tty width to determine this.
|
|
|
|
- int maxcmd = 0xfffff;
|
|
|
|
-
|
|
|
|
- sprintf(buf,"/proc/%u/maps",p->tgid);
|
|
|
|
- if(!freopen(buf, "r", stdin)) return 1;
|
|
|
|
-
|
|
|
|
- escape_command(cmdbuf, p, sizeof cmdbuf, &maxcmd, ESC_ARGS|ESC_BRACKETS);
|
|
|
|
- printf("%u: %s\n", p->tgid, cmdbuf);
|
|
|
|
-
|
|
|
|
- if(!q_option && (x_option|d_option)){
|
|
|
|
- if(x_option){
|
|
|
|
- if(sizeof(KLONG)==4) printf("Address Kbytes RSS Anon Locked Mode Mapping\n");
|
|
|
|
- else printf("Address Kbytes RSS Anon Locked Mode Mapping\n");
|
|
|
|
- }
|
|
|
|
- if(d_option){
|
|
|
|
- if(sizeof(KLONG)==4) printf("Address Kbytes Mode Offset Device Mapping\n");
|
|
|
|
- else printf("Address Kbytes Mode Offset Device Mapping\n");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- while(fgets(mapbuf,sizeof mapbuf,stdin)){
|
|
|
|
- char flags[32];
|
|
|
|
- char *tmp; // to clean up unprintables
|
|
|
|
- unsigned KLONG start, end, diff;
|
|
|
|
- unsigned long long file_offset, inode;
|
|
|
|
- unsigned dev_major, dev_minor;
|
|
|
|
- sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx %x:%x %Lu", &start, &end, flags, &file_offset, &dev_major, &dev_minor, &inode);
|
2009-05-15 21:45:51 +02:00
|
|
|
-
|
|
|
|
- if(start > range_high)
|
|
|
|
- break;
|
|
|
|
- if(end < range_low)
|
|
|
|
- continue;
|
|
|
|
-
|
2006-12-19 00:17:32 +01:00
|
|
|
- tmp = strchr(mapbuf,'\n');
|
|
|
|
- if(tmp) *tmp='\0';
|
|
|
|
- tmp = mapbuf;
|
|
|
|
- while(*tmp){
|
|
|
|
- if(!isprint(*tmp)) *tmp='?';
|
|
|
|
- tmp++;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- diff = end-start;
|
|
|
|
- if(flags[3]=='s') total_shared += diff;
|
|
|
|
- if(flags[3]=='p'){
|
|
|
|
- flags[3] = '-';
|
|
|
|
- if(flags[1]=='w') total_private_writeable += diff;
|
|
|
|
- else total_private_readonly += diff;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // format used by Solaris 9 and procps-3.2.0+
|
|
|
|
- // an 'R' if swap not reserved (MAP_NORESERVE, SysV ISM shared mem, etc.)
|
|
|
|
- flags[4] = '-';
|
|
|
|
- flags[5] = '\0';
|
|
|
|
-
|
|
|
|
- if(x_option){
|
|
|
|
- const char *cp = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
|
|
|
|
- printf(
|
|
|
|
- (sizeof(KLONG)==8)
|
|
|
|
- ? "%016"KLF"x %7lu - - - %s %s\n"
|
|
|
|
- : "%08lx %7lu - - - %s %s\n",
|
|
|
|
- start,
|
|
|
|
- (unsigned long)(diff>>10),
|
|
|
|
- flags,
|
|
|
|
- cp
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- if(d_option){
|
|
|
|
- const char *cp = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
|
|
|
|
- printf(
|
|
|
|
- (sizeof(KLONG)==8)
|
|
|
|
- ? "%016"KLF"x %7lu %s %016Lx %03x:%05x %s\n"
|
|
|
|
- : "%08lx %7lu %s %016Lx %03x:%05x %s\n",
|
|
|
|
- start,
|
|
|
|
- (unsigned long)(diff>>10),
|
|
|
|
- flags,
|
|
|
|
- file_offset,
|
|
|
|
- dev_major, dev_minor,
|
|
|
|
- cp
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- if(!x_option && !d_option){
|
|
|
|
- const char *cp = mapping_name(p, start, diff, mapbuf, 1, dev_major, dev_minor, inode);
|
|
|
|
- printf(
|
|
|
|
- (sizeof(KLONG)==8)
|
|
|
|
- ? "%016"KLF"x %6luK %s %s\n"
|
|
|
|
- : "%08lx %6luK %s %s\n",
|
|
|
|
- start,
|
|
|
|
- (unsigned long)(diff>>10),
|
|
|
|
- flags,
|
|
|
|
- cp
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
2009-05-15 21:45:51 +02:00
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
2006-12-19 00:17:32 +01:00
|
|
|
- if(!q_option){
|
|
|
|
- if(x_option){
|
|
|
|
- if(sizeof(KLONG)==8){
|
|
|
|
- printf("---------------- ------ ------ ------ ------\n");
|
|
|
|
- printf(
|
|
|
|
- "total kB %15ld - - -\n",
|
|
|
|
- (total_shared + total_private_writeable + total_private_readonly) >> 10
|
|
|
|
- );
|
|
|
|
- }else{
|
|
|
|
- printf("-------- ------- ------- ------- -------\n");
|
|
|
|
- printf(
|
|
|
|
- "total kB %7ld - - -\n",
|
|
|
|
- (total_shared + total_private_writeable + total_private_readonly) >> 10
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if(d_option){
|
|
|
|
- printf(
|
|
|
|
- "mapped: %ldK writeable/private: %ldK shared: %ldK\n",
|
|
|
|
- (total_shared + total_private_writeable + total_private_readonly) >> 10,
|
|
|
|
- total_private_writeable >> 10,
|
|
|
|
- total_shared >> 10
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- if(!x_option && !d_option){
|
|
|
|
- if(sizeof(KLONG)==8) printf(" total %16ldK\n", (total_shared + total_private_writeable + total_private_readonly) >> 10);
|
|
|
|
- else printf(" total %8ldK\n", (total_shared + total_private_writeable + total_private_readonly) >> 10);
|
|
|
|
- }
|
|
|
|
- }
|
2010-03-05 02:05:40 +01:00
|
|
|
-
|
2006-12-19 00:17:32 +01:00
|
|
|
- return 0;
|
|
|
|
+ printf("%s\n", obj_buff);
|
|
|
|
}
|
|
|
|
|
|
|
|
+int main(int argc, char *argv[])
|
|
|
|
+{
|
|
|
|
+ proc_t proc;
|
|
|
|
+ FILE *fp;
|
|
|
|
+ char path[PATH_MAX];
|
|
|
|
+ char buff[BUFFERSIZE];
|
|
|
|
+ int o, show_devices = 0, quiet = 0;
|
2009-05-15 21:45:51 +02:00
|
|
|
+ struct utsname uts;
|
2006-12-19 00:17:32 +01:00
|
|
|
+ pid_t pid;
|
|
|
|
+
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (uname(&uts) < 0) {
|
|
|
|
+ fprintf(stderr, "error getting information about current kernel: %m\n");
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+ sscanf(uts.release, "%d.%d.%d", &maj, &min, &patch);
|
|
|
|
+
|
2009-06-19 23:35:26 +02:00
|
|
|
+ if ((maj > 2) || ((maj == 2) && ((min > 6) || ((min == 6) && (patch >= 30)))))
|
|
|
|
+ dopage++;
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if ((maj > 2) || ((maj == 2) && ((min > 6) || ((min == 6) && (patch >= 27)))))
|
|
|
|
+ doswap++;
|
|
|
|
+ if ((maj > 2) || ((maj == 2) && ((min > 6) || ((min == 6) && (patch >= 25)))))
|
|
|
|
+ dopss++;
|
|
|
|
+ if ((maj < 2) || ((maj == 2) && ((min < 6) || ((min == 6) && (patch < 22)))))
|
|
|
|
+ noref++;
|
|
|
|
+
|
|
|
|
+ if ((lbits = sysconf(_SC_LONG_BIT)) < 0) {
|
|
|
|
+ fprintf(stderr, "error getting information about current kernel: %m\n");
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+
|
2006-12-19 00:17:32 +01:00
|
|
|
+ struct option longopts[] = {
|
|
|
|
+ { "help", 0, NULL, 'h' },
|
|
|
|
+ { "version", 0, NULL, 'V' },
|
|
|
|
+ { "quiet", 0, NULL, 'q' },
|
|
|
|
+ { "device", 0, NULL, 'd' },
|
2009-05-15 21:45:51 +02:00
|
|
|
+ { "limit", 0, NULL, 'A' },
|
2006-12-19 00:17:32 +01:00
|
|
|
+ { NULL, 0, NULL, 0 }
|
|
|
|
+ };
|
|
|
|
+
|
2009-05-15 21:45:51 +02:00
|
|
|
+ while ((o = getopt_long(argc, argv, "hqdA:V", longopts, NULL)) != -1) {
|
2006-12-19 00:17:32 +01:00
|
|
|
+ switch (o) {
|
|
|
|
+ case 'V':
|
|
|
|
+ display_version();
|
|
|
|
+ return 0;
|
|
|
|
+ case 'q':
|
|
|
|
+ quiet = 1;
|
|
|
|
+ break;
|
|
|
|
+ case 'd':
|
|
|
|
+ show_devices = 1;
|
|
|
|
+ break;
|
2009-05-15 21:45:51 +02:00
|
|
|
+ case 'A':
|
|
|
|
+ if (!optarg || *optarg == 0) {
|
|
|
|
+ usage(argv[0]);
|
|
|
|
+ return 1;
|
|
|
|
+ } else {
|
|
|
|
+ char *low = optarg;
|
|
|
|
+ char *high = strchr(low, ',');
|
|
|
|
+ if (high) {
|
|
|
|
+ *high = '\0';
|
|
|
|
+ high++;
|
|
|
|
+ }
|
|
|
|
+ if (low)
|
|
|
|
+ range_low = strtoull(low, &low, 16);
|
|
|
|
+ if (high)
|
|
|
|
+ range_high = strtoull(high, &high, 16);
|
|
|
|
+ if (*low || *high) {
|
|
|
|
+ usage(argv[0]);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ break;
|
2006-12-19 00:17:32 +01:00
|
|
|
+ case 'h':
|
|
|
|
+ usage(argv[0]);
|
|
|
|
+ return 0;
|
|
|
|
+ default:
|
|
|
|
+ usage(argv[0]);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (argc - optind > 0) {
|
|
|
|
+ errno = 0;
|
|
|
|
+ pid = strtoul(argv[optind], NULL, 10);
|
|
|
|
+ if (errno) {
|
|
|
|
+ perror("strtoul");
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ usage(argv[0]);
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!get_proc_stats(pid, &proc)) {
|
|
|
|
+ fprintf(stderr, "error getting process information for pid "
|
|
|
|
+ "%d from /proc/%d\n", pid, pid);
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ printf("%d: %s\n", pid, proc.cmd);
|
|
|
|
+
|
|
|
|
+ snprintf(path, PATH_MAX, "/proc/%d/maps", pid);
|
|
|
|
+ fp = fopen(path, "r");
|
|
|
|
+ if (!fp) {
|
|
|
|
+ perror("fopen");
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ snprintf(path, PATH_MAX, "/proc/%d/smaps", pid);
|
|
|
|
+ smaps_fp = fopen(path, "r");
|
|
|
|
+
|
|
|
|
+ if (!quiet) {
|
2009-05-15 21:45:51 +02:00
|
|
|
+ printf("START%s SIZE ", BLK);
|
2006-12-19 00:17:32 +01:00
|
|
|
+
|
|
|
|
+ if (smaps_fp) {
|
|
|
|
+ printf(" RSS ");
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (dopss)
|
|
|
|
+ printf(" PSS ");
|
2006-12-19 00:17:32 +01:00
|
|
|
+ printf(" DIRTY ");
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (doswap)
|
|
|
|
+ printf(" SWAP ");
|
2006-12-19 00:17:32 +01:00
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (show_devices)
|
|
|
|
+ printf("PERM OFFSET DEVICE MAPPING\n");
|
|
|
|
+ else
|
|
|
|
+ printf("PERM MAPPING\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (fgets(buff, BUFFERSIZE - 1, fp))
|
|
|
|
+ parse_line(pid, buff, show_devices);
|
|
|
|
+
|
|
|
|
+ if (!quiet) {
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (smaps_fp) {
|
|
|
|
+ printf("Total:%s ", BLK);
|
|
|
|
+ printf(" %6luK", mapped);
|
|
|
|
+ printf(" %6luK", rss);
|
|
|
|
+ if (dopss)
|
|
|
|
+ printf(" %6luK", pss);
|
|
|
|
+ printf(" %6luK", dirty);
|
|
|
|
+ if (doswap)
|
|
|
|
+ printf(" %6luK", swap);
|
|
|
|
+ printf("\n\n");
|
|
|
|
+ } else
|
2006-12-19 00:17:32 +01:00
|
|
|
+ printf("mapped: %luK ", mapped);
|
|
|
|
+
|
2009-05-15 21:45:51 +02:00
|
|
|
+ if (noref)
|
|
|
|
+ printf("%luK writable-private, %luK readonly-private, and %luK shared\n",
|
|
|
|
+ private, mapped - private - shared, shared);
|
|
|
|
+ else
|
|
|
|
+ printf("%luK writable-private, %luK readonly-private, %luK shared, and %luK referenced\n",
|
|
|
|
+ private, mapped - private - shared, shared, referenced);
|
2006-12-19 00:17:32 +01:00
|
|
|
+ }
|
|
|
|
|
|
|
|
-int main(int argc, char *argv[]){
|
|
|
|
- unsigned *pidlist;
|
|
|
|
- unsigned count = 0;
|
|
|
|
- PROCTAB* PT;
|
|
|
|
- proc_t p;
|
|
|
|
- int ret = 0;
|
|
|
|
-
|
|
|
|
- if(argc<2) usage();
|
|
|
|
- pidlist = malloc(sizeof(unsigned)*argc); // a bit more than needed perhaps
|
|
|
|
-
|
|
|
|
- while(*++argv){
|
|
|
|
- if(!strcmp("--version",*argv)){
|
|
|
|
- V_option++;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- if(**argv=='-'){
|
|
|
|
- char *walk = *argv;
|
|
|
|
- if(!walk[1]) usage();
|
|
|
|
- while(*++walk){
|
|
|
|
- switch(*walk){
|
|
|
|
- case 'V':
|
|
|
|
- V_option++;
|
|
|
|
- break;
|
|
|
|
- case 'x':
|
|
|
|
- x_option++;
|
|
|
|
- break;
|
|
|
|
- case 'r':
|
|
|
|
- r_option++;
|
|
|
|
- break;
|
|
|
|
- case 'd':
|
|
|
|
- d_option++;
|
|
|
|
- break;
|
|
|
|
- case 'q':
|
|
|
|
- q_option++;
|
|
|
|
- break;
|
2009-05-15 21:45:51 +02:00
|
|
|
- case 'A':{
|
|
|
|
- char *arg1;
|
|
|
|
- if(walk[1]){
|
|
|
|
- arg1 = walk+1;
|
|
|
|
- walk += strlen(walk)-1;
|
|
|
|
- }else{
|
|
|
|
- arg1 = *++argv;
|
|
|
|
- if(!arg1)
|
|
|
|
- usage();
|
|
|
|
- }
|
|
|
|
- char *arg2 = strchr(arg1,',');
|
|
|
|
- if(arg2)
|
|
|
|
- *arg2 = '\0';
|
|
|
|
- arg2 = arg2 ? arg2++ : arg1;
|
|
|
|
-
|
|
|
|
- if(*arg1)
|
|
|
|
- range_low = STRTOUKL(arg1,&arg1,16);
|
|
|
|
- if(*arg2)
|
|
|
|
- range_high = STRTOUKL(arg2,&arg2,16);
|
|
|
|
- if(*arg1 || *arg2)
|
|
|
|
- usage();
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- case 'a': // Sun prints anon/swap reservations
|
|
|
|
- case 'F': // Sun forces hostile ptrace-like grab
|
|
|
|
- case 'l': // Sun shows unresolved dynamic names
|
|
|
|
- case 'L': // Sun shows lgroup info
|
|
|
|
- case 's': // Sun shows page sizes
|
|
|
|
- case 'S': // Sun shows swap reservations
|
2006-12-19 00:17:32 +01:00
|
|
|
- default:
|
|
|
|
- usage();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }else{
|
|
|
|
- char *walk = *argv;
|
|
|
|
- char *endp;
|
|
|
|
- unsigned long pid;
|
|
|
|
- if(!strncmp("/proc/",walk,6)){
|
|
|
|
- walk += 6;
|
|
|
|
- // user allowed to do: pmap /proc/*
|
|
|
|
- if(*walk<'0' || *walk>'9') continue;
|
|
|
|
- }
|
|
|
|
- if(*walk<'0' || *walk>'9') usage();
|
|
|
|
- pid = strtoul(walk, &endp, 0);
|
|
|
|
- if(pid<1ul || pid>0x7ffffffful || *endp) usage();
|
|
|
|
- pidlist[count++] = pid;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if( (x_option|V_option|r_option|d_option|q_option) >> 1 ) usage(); // dupes
|
|
|
|
- if(V_option){
|
|
|
|
- if(count|x_option|r_option|d_option|q_option) usage();
|
|
|
|
- fprintf(stdout, "pmap (%s)\n", procps_version);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- if(count<1) usage(); // no processes
|
|
|
|
- if(d_option && x_option) usage();
|
|
|
|
-
|
|
|
|
- discover_shm_minor();
|
|
|
|
-
|
|
|
|
- pidlist[count] = 0; // old libproc interface is zero-terminated
|
|
|
|
- PT = openproc(PROC_FILLSTAT|PROC_FILLARG|PROC_PID, pidlist);
|
|
|
|
- while(readproc(PT, &p)){
|
|
|
|
- ret |= one_proc(&p);
|
|
|
|
- if(p.cmdline) free((void*)*p.cmdline);
|
|
|
|
- count--;
|
|
|
|
- }
|
|
|
|
- closeproc(PT);
|
|
|
|
-
|
|
|
|
- if(count) ret |= 42; // didn't find all processes asked for
|
|
|
|
- return ret;
|
|
|
|
+ return 0;
|
|
|
|
}
|