showmap.c revision 7341494707810f709855ea85ce03a8ec3ac8dbaf
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
82    if(skip) {
83        free(mi);
84        goto again;
85    }
86
87    return mi;
88oops:
89    free(mi);
90    return 0;
91}
92
93
94mapinfo *load_maps(int pid, int verbose)
95{
96    char tmp[128];
97    FILE *fp;
98    mapinfo *milist = 0;
99    mapinfo *mi;
100
101    sprintf(tmp, "/proc/%d/smaps", pid);
102    fp = fopen(tmp, "r");
103    if(fp == 0) return 0;
104
105    while((mi = read_mapinfo(fp)) != 0) {
106            /* if not verbose, coalesce mappings from the same entity */
107        if(!verbose && milist) {
108            if((!strcmp(mi->name, milist->name) && (mi->name[0] != '['))
109               || !strcmp(mi->name,"[lib_bss]")) {
110                milist->size += mi->size;
111                milist->rss += mi->rss;
112                milist->pss += mi->pss;
113                milist->shared_clean += mi->shared_clean;
114                milist->shared_dirty += mi->shared_dirty;
115                milist->private_clean += mi->private_clean;
116                milist->private_dirty += mi->private_dirty;
117                milist->end = mi->end;
118                free(mi);
119                continue;
120            }
121        }
122
123        mi->next = milist;
124        milist = mi;
125    }
126    fclose(fp);
127
128    return milist;
129}
130
131static int verbose = 0;
132static int terse = 0;
133static int addresses = 0;
134
135int show_map(int pid)
136{
137    mapinfo *milist;
138    mapinfo *mi;
139    unsigned shared_dirty = 0;
140    unsigned shared_clean = 0;
141    unsigned private_dirty = 0;
142    unsigned private_clean = 0;
143    unsigned rss = 0;
144    unsigned pss = 0;
145    unsigned size = 0;
146
147    milist = load_maps(pid, verbose);
148    if(milist == 0) {
149        fprintf(stderr,"cannot get /proc/smaps for pid %d\n", pid);
150        return 1;
151    }
152
153    if(addresses) {
154        printf("start    end      shared   private  object\n");
155        printf("-------- -------- -------- -------- ------------------------------\n");
156    } else {
157        printf("virtual                    shared   shared   private  private\n");
158        printf("size     RSS      PSS      clean    dirty    clean    dirty    object\n");
159        printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
160    }
161    for(mi = milist; mi; mi = mi->next){
162        shared_clean += mi->shared_clean;
163        shared_dirty += mi->shared_dirty;
164        private_clean += mi->private_clean;
165        private_dirty += mi->private_dirty;
166        rss += mi->rss;
167        pss += mi->pss;
168        size += mi->size;
169
170        if(terse && !mi->private_dirty) continue;
171
172        if(addresses) {
173            printf("%08x %08x %8d %8d %s\n", mi->start, mi->end,
174                   mi->shared_clean + mi->shared_dirty,
175                   mi->private_clean + mi->private_dirty,
176                   mi->name);
177        } else {
178            printf("%8d %8d %8d %8d %8d %8d %8d %s\n", mi->size,
179                   mi->rss,
180                   mi->pss,
181                   mi->shared_clean, mi->shared_dirty,
182                   mi->private_clean, mi->private_dirty,
183                   mi->name);
184        }
185    }
186    if(addresses) {
187        printf("-------- -------- -------- -------- ------------------------------\n");
188        printf("                  %8d %8d TOTAL\n",
189               shared_dirty + shared_clean,
190               private_dirty + private_clean);
191    } else {
192        printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
193        printf("%8d %8d %8d %8d %8d %8d %8d TOTAL\n", size,
194               rss, pss,
195               shared_clean, shared_dirty,
196               private_clean, private_dirty);
197    }
198    return 0;
199}
200
201int main(int argc, char *argv[])
202{
203    int usage = 1;
204
205    for(argc--, argv++; argc > 0; argc--, argv++) {
206        if(!strcmp(argv[0],"-v")) {
207            verbose = 1;
208            continue;
209        }
210        if(!strcmp(argv[0],"-t")) {
211            terse = 1;
212            continue;
213        }
214        if(!strcmp(argv[0],"-a")) {
215            addresses = 1;
216            continue;
217        }
218        show_map(atoi(argv[0]));
219        usage = 0;
220    }
221
222    if(usage) {
223        fprintf(stderr,
224                "showmap [-t] [-v] [-c] <pid>\n"
225                "        -t = terse (show only items with private pages)\n"
226                "        -v = verbose (don't coalesce adjacant maps)\n"
227                "        -a = addresses (show virtual memory map)\n"
228                );
229    }
230
231	return 0;
232}
233