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 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; 92oops: 93 fprintf(stderr, "WARNING: Format of /proc/<pid>/smaps has changed!\n"); 94 free(mi); 95 return 0; 96} 97 98 99mapinfo *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 136static int verbose = 0; 137static int terse = 0; 138static int addresses = 0; 139 140int 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 206int 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