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