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