OSDN Git Service

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