Home | History | Annotate | Download | only in showmap
      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 }
    238