1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/* pmap.c - Reports the memory map of a process or processes.
*
* Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
* Copyright 2013 Kyungwan Han <asura321@gmail.com>
*
* No Standard.
*
USE_PMAP(NEWTOY(pmap, "xq", TOYFLAG_BIN))
config PMAP
bool "pmap"
default y
help
usage: pmap [-xq] [pids...]
Reports the memory map of a process or processes.
-x Show the extended format.
-q Do not display some header/footer lines.
*/
#define FOR_pmap
#include "toys.h"
#if ULONG_MAX == 0xffffffff
# define TAB "\t"
# define WIDTH "8"
# define DASHES ""
#else
# define TAB "\t\t"
# define WIDTH "16"
# define DASHES "--------"
#endif
struct _smaps {
unsigned long start_addr, size, pss, pdirty, swap;
char mode[5], *mapping;
};
//Display mapping info.
static void show_maps(struct _smaps *map)
{
xprintf("%0" WIDTH "lx ", map->start_addr);
if (toys.optflags & FLAG_x)
xprintf("%7lu %7lu %7lu %7lu ", map->size, map->pss, map->pdirty, map->swap);
else xprintf("%7luK", map->size);
xprintf(" %.4s \n", map->mode, map->mapping);
free(map->mapping);
}
//Read "/proc/pid/smaps" file and extract data.
static int read_smaps(pid_t pid, struct _smaps *total)
{
struct _smaps curmap;
char *line;
int fd, nitems;
snprintf(toybuf, sizeof(toybuf), "/proc/%u/smaps", pid);
if ((fd = open(toybuf, O_RDONLY)) < 0) return fd;
memset(&curmap, 0, sizeof(struct _smaps));
while ((line = get_line(fd))) {
char *ptr = NULL;
*toybuf = *(toybuf+34) = *(toybuf+40) = '\0';
//1st line format -> start_addr-End_addr rw-s ADR M:m OFS
if ((ptr = strchr(line, '-'))) {
if (curmap.size) show_maps(&curmap);
memset(&curmap, 0, sizeof(struct _smaps));
nitems = sscanf(line, "%s %s %*s %*s %*s %s\n", toybuf, toybuf+34, toybuf+40);
if (nitems >= 2) {
ptr = strchr(toybuf, '-');
*ptr = '\0';
total->size += curmap.size = (strtoul(++ptr, NULL, 16) -
(curmap.start_addr = strtoul(toybuf, NULL, 16))) >> 10;
strncpy(curmap.mode, toybuf+34, sizeof(curmap.mode)-1);
if (!*(toybuf+40)) curmap.mapping = xstrdup(" [ anon ]");
else curmap.mapping = xstrdup(toybuf+40);
}
} else { //2nd line onwards..
unsigned long val = 0;
nitems = sscanf(line, "%s %lu\n", toybuf, &val);
if (nitems == 2) {
if (!strcmp("Pss:", toybuf)) total->pss += (curmap.pss = val);
else if (!strcmp("Private_Dirty:", toybuf)) total->pdirty += (curmap.pdirty = val);
else if (!strcmp("Swap:", toybuf)) total->swap += (curmap.swap = val);
}
}
free(line);
}
if (curmap.size) show_maps(&curmap);
xclose(fd);
return 0;
}
void pmap_main(void)
{
struct _smaps total;
int fd;
while (*toys.optargs) {
pid_t pid = get_int_value(*toys.optargs++, 0, INT_MAX);
snprintf(toybuf, sizeof(toybuf), "/proc/%u/cmdline", pid);
if ((fd = open(toybuf, O_RDONLY)) == -1) xprintf("%u: [no such process]\n", pid);
else {
ssize_t len = readall(fd, toybuf, sizeof(toybuf) -1);
if (len <= 0) xprintf("%u: [no such process]\n", (int)pid);
else {
toybuf[len] = '\0';
while (--len >= 0 && toybuf[len] == '\0') continue;
for (; len > 0; len--)
if ((unsigned char)toybuf[len] < ' ') toybuf[len] = ' ';
xprintf("%u: %s\n", (int)pid, toybuf);
}
xclose(fd);
}
if (!(toys.optflags & FLAG_q) && (toys.optflags & FLAG_x))
xprintf("Address" TAB " Kbytes PSS Dirty Swap Mode Mapping\n");
memset(&total, 0, sizeof(struct _smaps));
if (read_smaps(pid, &total)) toys.exitval = 42;
else { //to display total mapping.
if (!(toys.optflags & FLAG_q) )
(toys.optflags & FLAG_x)
? xprintf("--------" DASHES " ------ ------ ------ ------\n"
"total" TAB " %7lu %7lu %7lu %7lu\n",
total.size, total.pss, total.pdirty, total.swap)
: xprintf("mapped: %luK\n", total.size);
}
}
}
|