showmap.c revision e16cb84e2324f05334d18dcf5956f20f44262b62
1#include <stdio.h>
2#include <stdlib.h>
3#include <math.h>
4#include <string.h>
5#include <errno.h>
6#include <unistd.h>
7#include <fcntl.h>
8
9#include <ctype.h>
10#include <stddef.h>
11
12typedef struct mapinfo mapinfo;
13
14struct mapinfo {
15    mapinfo *next;
16    unsigned start;
17    unsigned end;
18    unsigned size;
19    unsigned rss;
20    unsigned pss;
21    unsigned shared_clean;
22    unsigned shared_dirty;
23    unsigned private_clean;
24    unsigned private_dirty;
25    char name[1];
26};
27
28// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /android/lib/libcomposer.so
29// 012345678901234567890123456789012345678901234567890123456789
30// 0         1         2         3         4         5
31
32mapinfo *read_mapinfo(FILE *fp)
33{
34    char line[1024];
35    mapinfo *mi;
36    int len;
37    int skip;
38
39again:
40    skip = 0;
41
42    if(fgets(line, 1024, fp) == 0) return 0;
43
44    len = strlen(line);
45    if(len < 1) return 0;
46    line[--len] = 0;
47
48    mi = calloc(1, sizeof(mapinfo) + len + 16);
49    if(mi == 0) return 0;
50
51    mi->start = strtoul(line, 0, 16);
52    mi->end = strtoul(line + 9, 0, 16);
53
54    if(len < 50) {
55        if((mi->start >= 0x10000000) && (mi->start < 0x40000000)) {
56            strcpy(mi->name, "[stack]");
57        } else if(mi->start > 0x50000000) {
58            strcpy(mi->name, "[lib_bss]");
59        } else {
60            strcpy(mi->name, "[anon]");
61        }
62    } else {
63        strcpy(mi->name, line + 49);
64    }
65
66    if(fgets(line, 1024, fp) == 0) goto oops;
67    if(sscanf(line, "Size: %d kB", &mi->size) != 1) goto oops;
68    if(fgets(line, 1024, fp) == 0) goto oops;
69    if(sscanf(line, "Rss: %d kB", &mi->rss) != 1) goto oops;
70    if(fgets(line, 1024, fp) == 0) goto oops;
71    if(sscanf(line, "Pss: %d kB", &mi->pss) == 1)
72        if(fgets(line, 1024, fp) == 0) goto oops;
73    if(sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) != 1) goto oops;
74    if(fgets(line, 1024, fp) == 0) goto oops;
75    if(sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) != 1) goto oops;
76    if(fgets(line, 1024, fp) == 0) goto oops;
77    if(sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1) goto oops;
78    if(fgets(line, 1024, fp) == 0) goto oops;
79    if(sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1) goto oops;
80    if(fgets(line, 1024, fp) == 0) goto oops;
81    if(fgets(line, 1024, fp) == 0) goto oops;
82
83    if(skip) {
84        free(mi);
85        goto again;
86    }
87
88    return mi;
89oops:
90    fprintf(stderr, "WARNING: Format of /proc/<pid>/smaps has changed!\n");
91    free(mi);
92    return 0;
93}
94
95
96mapinfo *load_maps(int pid, int verbose)
97{
98    char tmp[128];
99    FILE *fp;
100    mapinfo *milist = 0;
101    mapinfo *mi;
102
103    sprintf(tmp, "/proc/%d/smaps", pid);
104    fp = fopen(tmp, "r");
105    if(fp == 0) return 0;
106
107    while((mi = read_mapinfo(fp)) != 0) {
108            /* if not verbose, coalesce mappings from the same entity */
109        if(!verbose && milist) {
110            if((!strcmp(mi->name, milist->name) && (mi->name[0] != '['))
111               || !strcmp(mi->name,"[lib_bss]")) {
112                milist->size += mi->size;
113                milist->rss += mi->rss;
114                milist->pss += mi->pss;
115                milist->shared_clean += mi->shared_clean;
116                milist->shared_dirty += mi->shared_dirty;
117                milist->private_clean += mi->private_clean;
118                milist->private_dirty += mi->private_dirty;
119                milist->end = mi->end;
120                free(mi);
121                continue;
122            }
123        }
124
125        mi->next = milist;
126        milist = mi;
127    }
128    fclose(fp);
129
130    return milist;
131}
132
133static int verbose = 0;
134static int terse = 0;
135static int addresses = 0;
136
137int show_map(int pid)
138{
139    mapinfo *milist;
140    mapinfo *mi;
141    unsigned shared_dirty = 0;
142    unsigned shared_clean = 0;
143    unsigned private_dirty = 0;
144    unsigned private_clean = 0;
145    unsigned rss = 0;
146    unsigned pss = 0;
147    unsigned size = 0;
148
149    milist = load_maps(pid, verbose);
150    if(milist == 0) {
151        fprintf(stderr,"cannot get /proc/smaps for pid %d\n", pid);
152        return 1;
153    }
154
155    if(addresses) {
156        printf("start    end      shared   private  object\n");
157        printf("-------- -------- -------- -------- ------------------------------\n");
158    } else {
159        printf("virtual                    shared   shared   private  private\n");
160        printf("size     RSS      PSS      clean    dirty    clean    dirty    object\n");
161        printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
162    }
163    for(mi = milist; mi; mi = mi->next){
164        shared_clean += mi->shared_clean;
165        shared_dirty += mi->shared_dirty;
166        private_clean += mi->private_clean;
167        private_dirty += mi->private_dirty;
168        rss += mi->rss;
169        pss += mi->pss;
170        size += mi->size;
171
172        if(terse && !mi->private_dirty) continue;
173
174        if(addresses) {
175            printf("%08x %08x %8d %8d %s\n", mi->start, mi->end,
176                   mi->shared_clean + mi->shared_dirty,
177                   mi->private_clean + mi->private_dirty,
178                   mi->name);
179        } else {
180            printf("%8d %8d %8d %8d %8d %8d %8d %s\n", mi->size,
181                   mi->rss,
182                   mi->pss,
183                   mi->shared_clean, mi->shared_dirty,
184                   mi->private_clean, mi->private_dirty,
185                   mi->name);
186        }
187    }
188    if(addresses) {
189        printf("-------- -------- -------- -------- ------------------------------\n");
190        printf("                  %8d %8d TOTAL\n",
191               shared_dirty + shared_clean,
192               private_dirty + private_clean);
193    } else {
194        printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
195        printf("%8d %8d %8d %8d %8d %8d %8d TOTAL\n", size,
196               rss, pss,
197               shared_clean, shared_dirty,
198               private_clean, private_dirty);
199    }
200    return 0;
201}
202
203int main(int argc, char *argv[])
204{
205    int usage = 1;
206
207    for(argc--, argv++; argc > 0; argc--, argv++) {
208        if(!strcmp(argv[0],"-v")) {
209            verbose = 1;
210            continue;
211        }
212        if(!strcmp(argv[0],"-t")) {
213            terse = 1;
214            continue;
215        }
216        if(!strcmp(argv[0],"-a")) {
217            addresses = 1;
218            continue;
219        }
220        show_map(atoi(argv[0]));
221        usage = 0;
222    }
223
224    if(usage) {
225        fprintf(stderr,
226                "showmap [-t] [-v] [-c] <pid>\n"
227                "        -t = terse (show only items with private pages)\n"
228                "        -v = verbose (don't coalesce adjacant maps)\n"
229                "        -a = addresses (show virtual memory map)\n"
230                );
231    }
232
233	return 0;
234}
235