showmap.c revision fda77ea946fa4c58775d5ff63895cf9d41d3b568
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 32int parse_header(char* line, int len, mapinfo** mi) { 33 unsigned long start; 34 unsigned long end; 35 char name[128]; 36 37 name[0] = '\0'; 38 39 // Sometimes the name is missing. 40 if (sscanf(line, "%lx-%lx %*s %*lx %*x:%*x %*ld %127s", &start, &end, name) < 2) { 41 return 0; 42 } 43 44 if (name[0] == '\0') { 45 if ((start >= 0x10000000) && (start < 0x40000000)) { 46 strlcpy(name, "[stack]", sizeof(name)); 47 } else if (start > 0x50000000) { 48 strlcpy(name, "[lib_bss]", sizeof(name)); 49 } else { 50 strlcpy(name, "[anon]", sizeof(name)); 51 } 52 } 53 54 const int name_size = strlen(name) + 1; 55 struct mapinfo* info = calloc(1, sizeof(mapinfo) + name_size); 56 if (info == NULL) { 57 return -1; 58 } 59 60 info->start = start; 61 info->end = end; 62 strlcpy(info->name, name, name_size); 63 64 *mi = info; 65 66 return 0; 67} 68 69int parse_field(mapinfo* mi, char* line) { 70 char field[64]; 71 int size; 72 73 if (sscanf(line, "%63s %d kB", field, &size) != 2) { 74 return -1; 75 } 76 77 if (!strcmp(field, "Size:")) { 78 mi->size = size; 79 } else if (!strcmp(field, "Rss:")) { 80 mi->rss = size; 81 } else if (!strcmp(field, "Pss:")) { 82 mi->pss = size; 83 } else if (!strcmp(field, "Shared_Clean:")) { 84 mi->shared_clean = size; 85 } else if (!strcmp(field, "Shared_Dirty:")) { 86 mi->shared_dirty = size; 87 } else if (!strcmp(field, "Private_Clean:")) { 88 mi->private_clean = size; 89 } else if (!strcmp(field, "Private_Dirty:")) { 90 mi->private_dirty = size; 91 } 92 93 return 0; 94} 95 96mapinfo *read_mapinfo(FILE *fp) 97{ 98 char line[1024]; 99 mapinfo *current = NULL; 100 int len; 101 int skip; 102 103 while (fgets(line, sizeof(line), fp) != 0) { 104 if (current != NULL) { 105 parse_field(current, line); 106 } 107 108 len = strlen(line); 109 if (len < 1) { 110 return NULL; 111 } 112 line[--len] = 0; 113 114 mapinfo *next = NULL; 115 if (parse_header(line, len, &next) < 0) { 116 goto err; 117 } else if (next != NULL) { 118 next->next = current; 119 current = next; 120 continue; 121 } 122 } 123 124 return current; 125 126err: 127 while (current != NULL) { 128 mapinfo* next = current->next; 129 free(current); 130 current = next; 131 } 132 133 return NULL; 134} 135 136 137mapinfo *load_maps(int pid, int verbose) 138{ 139 char tmp[128]; 140 FILE *fp; 141 mapinfo *milist = 0; 142 mapinfo *mi; 143 144 snprintf(tmp, sizeof(tmp), "/proc/%d/smaps", pid); 145 fp = fopen(tmp, "r"); 146 if (fp == 0) { 147 fprintf(stderr, "cannot open /proc/%d/smaps: %s\n", pid, strerror(errno)); 148 return NULL; 149 } 150 151 milist = read_mapinfo(fp); 152 fclose(fp); 153 154 if (!milist) { 155 fprintf(stderr, "could not read /proc/%d/smaps\n", pid); 156 return NULL; 157 } 158 159 /* if not verbose, coalesce mappings from the same entity */ 160 if (!verbose) { 161 mapinfo* current = milist; 162 mapinfo* last = NULL; 163 164 while (current != NULL) { 165 mapinfo* next = current->next; 166 167 if (last != NULL 168 && ((current->name[0] != '[' && !strcmp(last->name, current->name)) 169 || !strcmp(current->name, "[lib_bss]"))) { 170 last->size += current->size; 171 last->rss += current->rss; 172 last->pss += current->pss; 173 last->shared_clean += current->shared_clean; 174 last->shared_dirty += current->shared_dirty; 175 last->private_clean += current->private_clean; 176 last->private_dirty += current->private_dirty; 177 last->end = current->end; 178 179 last->next = next; 180 free(current); 181 } else { 182 last = current; 183 } 184 185 current = next; 186 } 187 } 188 189 return milist; 190} 191 192static int verbose = 0; 193static int terse = 0; 194static int addresses = 0; 195 196int show_map(int pid) 197{ 198 mapinfo *milist; 199 mapinfo *mi; 200 unsigned shared_dirty = 0; 201 unsigned shared_clean = 0; 202 unsigned private_dirty = 0; 203 unsigned private_clean = 0; 204 unsigned rss = 0; 205 unsigned pss = 0; 206 unsigned size = 0; 207 208 milist = load_maps(pid, verbose); 209 if (milist == NULL) { 210 return 1; 211 } 212 213 if (addresses) { 214 printf("start end shared private object\n"); 215 printf("-------- -------- -------- -------- ------------------------------\n"); 216 } else { 217 printf("virtual shared shared private private\n"); 218 printf("size RSS PSS clean dirty clean dirty object\n"); 219 printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n"); 220 } 221 222 for (mi = milist; mi;) { 223 mapinfo* last = mi; 224 225 shared_clean += mi->shared_clean; 226 shared_dirty += mi->shared_dirty; 227 private_clean += mi->private_clean; 228 private_dirty += mi->private_dirty; 229 rss += mi->rss; 230 pss += mi->pss; 231 size += mi->size; 232 233 if (terse && !mi->private_dirty) { 234 goto out; 235 } 236 237 if (addresses) { 238 printf("%08x %08x %8d %8d %s\n", mi->start, mi->end, 239 mi->shared_clean + mi->shared_dirty, 240 mi->private_clean + mi->private_dirty, 241 mi->name); 242 } else { 243 printf("%8d %8d %8d %8d %8d %8d %8d %s\n", mi->size, 244 mi->rss, 245 mi->pss, 246 mi->shared_clean, mi->shared_dirty, 247 mi->private_clean, mi->private_dirty, 248 mi->name); 249 } 250 251out: 252 mi = mi->next; 253 free(last); 254 } 255 256 if (addresses) { 257 printf("-------- -------- -------- -------- ------------------------------\n"); 258 printf(" %8d %8d TOTAL\n", 259 shared_dirty + shared_clean, 260 private_dirty + private_clean); 261 } else { 262 printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n"); 263 printf("%8d %8d %8d %8d %8d %8d %8d TOTAL\n", size, 264 rss, pss, 265 shared_clean, shared_dirty, 266 private_clean, private_dirty); 267 } 268 269 return 0; 270} 271 272int main(int argc, char *argv[]) 273{ 274 int usage = 1; 275 276 for (argc--, argv++; argc > 0; argc--, argv++) { 277 if (!strcmp(argv[0],"-v")) { 278 verbose = 1; 279 continue; 280 } 281 if (!strcmp(argv[0],"-t")) { 282 terse = 1; 283 continue; 284 } 285 if (!strcmp(argv[0],"-a")) { 286 addresses = 1; 287 continue; 288 } 289 show_map(atoi(argv[0])); 290 usage = 0; 291 } 292 293 if (usage) { 294 fprintf(stderr, 295 "showmap [-t] [-v] [-c] <pid>\n" 296 " -t = terse (show only items with private pages)\n" 297 " -v = verbose (don't coalesce adjacant maps)\n" 298 " -a = addresses (show virtual memory map)\n" 299 ); 300 } 301 302 return 0; 303} 304