summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenny Root <kroot@google.com>2011-07-06 14:59:57 -0700
committerKenny Root <kroot@google.com>2011-07-07 21:58:52 -0700
commitfda77ea946fa4c58775d5ff63895cf9d41d3b568 (patch)
treee4916e7f23eccea5f7548ff3b3ac27c1d0bed670
parentdba332410528d11474ae9f878b6984755d55e299 (diff)
downloadextras-fda77ea946fa4c58775d5ff63895cf9d41d3b568.tar.gz
More robust parsing for smaps
Change-Id: Ica273bf302bbc5025e48aa62eff5bf64fbdcac77
-rw-r--r--showmap/showmap.c244
1 files changed, 155 insertions, 89 deletions
diff --git a/showmap/showmap.c b/showmap/showmap.c
index 2a028eea..0a9a58ab 100644
--- a/showmap/showmap.c
+++ b/showmap/showmap.c
@@ -29,70 +29,108 @@ struct mapinfo {
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
+int parse_header(char* line, int len, mapinfo** mi) {
+ unsigned long start;
+ unsigned long end;
+ char name[128];
+
+ name[0] = '\0';
+
+ // Sometimes the name is missing.
+ if (sscanf(line, "%lx-%lx %*s %*lx %*x:%*x %*ld %127s", &start, &end, name) < 2) {
+ return 0;
+ }
+
+ if (name[0] == '\0') {
+ if ((start >= 0x10000000) && (start < 0x40000000)) {
+ strlcpy(name, "[stack]", sizeof(name));
+ } else if (start > 0x50000000) {
+ strlcpy(name, "[lib_bss]", sizeof(name));
+ } else {
+ strlcpy(name, "[anon]", sizeof(name));
+ }
+ }
+
+ const int name_size = strlen(name) + 1;
+ struct mapinfo* info = calloc(1, sizeof(mapinfo) + name_size);
+ if (info == NULL) {
+ return -1;
+ }
+
+ info->start = start;
+ info->end = end;
+ strlcpy(info->name, name, name_size);
+
+ *mi = info;
+
+ return 0;
+}
+
+int parse_field(mapinfo* mi, char* line) {
+ char field[64];
+ int size;
+
+ if (sscanf(line, "%63s %d kB", field, &size) != 2) {
+ return -1;
+ }
+
+ if (!strcmp(field, "Size:")) {
+ mi->size = size;
+ } else if (!strcmp(field, "Rss:")) {
+ mi->rss = size;
+ } else if (!strcmp(field, "Pss:")) {
+ mi->pss = size;
+ } else if (!strcmp(field, "Shared_Clean:")) {
+ mi->shared_clean = size;
+ } else if (!strcmp(field, "Shared_Dirty:")) {
+ mi->shared_dirty = size;
+ } else if (!strcmp(field, "Private_Clean:")) {
+ mi->private_clean = size;
+ } else if (!strcmp(field, "Private_Dirty:")) {
+ mi->private_dirty = size;
+ }
+
+ return 0;
+}
+
mapinfo *read_mapinfo(FILE *fp)
{
char line[1024];
- mapinfo *mi;
+ mapinfo *current = NULL;
int len;
int skip;
-again:
- skip = 0;
-
- if(fgets(line, 1024, fp) == 0) return 0;
+ while (fgets(line, sizeof(line), fp) != 0) {
+ if (current != NULL) {
+ parse_field(current, line);
+ }
+
+ len = strlen(line);
+ if (len < 1) {
+ return NULL;
+ }
+ line[--len] = 0;
- len = strlen(line);
- if(len < 1) return 0;
- line[--len] = 0;
+ mapinfo *next = NULL;
+ if (parse_header(line, len, &next) < 0) {
+ goto err;
+ } else if (next != NULL) {
+ next->next = current;
+ current = next;
+ continue;
+ }
+ }
- mi = calloc(1, sizeof(mapinfo) + len + 16);
- if(mi == 0) return 0;
+ return current;
- mi->start = strtoul(line, 0, 16);
- mi->end = strtoul(line + 9, 0, 16);
+err:
+ while (current != NULL) {
+ mapinfo* next = current->next;
+ free(current);
+ current = next;
+ }
- if(len < 50) {
- if((mi->start >= 0x10000000) && (mi->start < 0x40000000)) {
- strcpy(mi->name, "[stack]");
- } else if(mi->start > 0x50000000) {
- strcpy(mi->name, "[lib_bss]");
- } else {
- strcpy(mi->name, "[anon]");
- }
- } else {
- strcpy(mi->name, line + 49);
- }
-
- if(fgets(line, 1024, fp) == 0) goto oops;
- if(sscanf(line, "Size: %d kB", &mi->size) != 1) goto oops;
- if(fgets(line, 1024, fp) == 0) goto oops;
- if(sscanf(line, "Rss: %d kB", &mi->rss) != 1) goto oops;
- if(fgets(line, 1024, fp) == 0) goto oops;
- if(sscanf(line, "Pss: %d kB", &mi->pss) == 1)
- if(fgets(line, 1024, fp) == 0) goto oops;
- if(sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) != 1) goto oops;
- if(fgets(line, 1024, fp) == 0) goto oops;
- if(sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) != 1) goto oops;
- if(fgets(line, 1024, fp) == 0) goto oops;
- if(sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1) goto oops;
- if(fgets(line, 1024, fp) == 0) goto oops;
- if(sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1) goto oops;
-
- if(fgets(line, 1024, fp) == 0) goto oops; // Referenced
- if(fgets(line, 1024, fp) == 0) goto oops; // Swap
- if(fgets(line, 1024, fp) == 0) goto oops; // KernelPageSize
- if(fgets(line, 1024, fp) == 0) goto oops; // MMUPageSize
-
- if(skip) {
- free(mi);
- goto again;
- }
-
- return mi;
-oops:
- fprintf(stderr, "WARNING: Format of /proc/<pid>/smaps has changed!\n");
- free(mi);
- return 0;
+ return NULL;
}
@@ -103,33 +141,51 @@ mapinfo *load_maps(int pid, int verbose)
mapinfo *milist = 0;
mapinfo *mi;
- sprintf(tmp, "/proc/%d/smaps", pid);
+ snprintf(tmp, sizeof(tmp), "/proc/%d/smaps", pid);
fp = fopen(tmp, "r");
- if(fp == 0) return 0;
+ if (fp == 0) {
+ fprintf(stderr, "cannot open /proc/%d/smaps: %s\n", pid, strerror(errno));
+ return NULL;
+ }
+
+ milist = read_mapinfo(fp);
+ fclose(fp);
+
+ if (!milist) {
+ fprintf(stderr, "could not read /proc/%d/smaps\n", pid);
+ return NULL;
+ }
- while((mi = read_mapinfo(fp)) != 0) {
- /* if not verbose, coalesce mappings from the same entity */
- if(!verbose && milist) {
- if((!strcmp(mi->name, milist->name) && (mi->name[0] != '['))
- || !strcmp(mi->name,"[lib_bss]")) {
- milist->size += mi->size;
- milist->rss += mi->rss;
- milist->pss += mi->pss;
- milist->shared_clean += mi->shared_clean;
- milist->shared_dirty += mi->shared_dirty;
- milist->private_clean += mi->private_clean;
- milist->private_dirty += mi->private_dirty;
- milist->end = mi->end;
- free(mi);
- continue;
+ /* if not verbose, coalesce mappings from the same entity */
+ if (!verbose) {
+ mapinfo* current = milist;
+ mapinfo* last = NULL;
+
+ while (current != NULL) {
+ mapinfo* next = current->next;
+
+ if (last != NULL
+ && ((current->name[0] != '[' && !strcmp(last->name, current->name))
+ || !strcmp(current->name, "[lib_bss]"))) {
+ last->size += current->size;
+ last->rss += current->rss;
+ last->pss += current->pss;
+ last->shared_clean += current->shared_clean;
+ last->shared_dirty += current->shared_dirty;
+ last->private_clean += current->private_clean;
+ last->private_dirty += current->private_dirty;
+ last->end = current->end;
+
+ last->next = next;
+ free(current);
+ } else {
+ last = current;
}
- }
- mi->next = milist;
- milist = mi;
+ current = next;
+ }
}
- fclose(fp);
-
+
return milist;
}
@@ -150,12 +206,11 @@ int show_map(int pid)
unsigned size = 0;
milist = load_maps(pid, verbose);
- if(milist == 0) {
- fprintf(stderr,"cannot get /proc/smaps for pid %d\n", pid);
+ if (milist == NULL) {
return 1;
}
- if(addresses) {
+ if (addresses) {
printf("start end shared private object\n");
printf("-------- -------- -------- -------- ------------------------------\n");
} else {
@@ -163,7 +218,10 @@ int show_map(int pid)
printf("size RSS PSS clean dirty clean dirty object\n");
printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
}
- for(mi = milist; mi; mi = mi->next){
+
+ for (mi = milist; mi;) {
+ mapinfo* last = mi;
+
shared_clean += mi->shared_clean;
shared_dirty += mi->shared_dirty;
private_clean += mi->private_clean;
@@ -172,9 +230,11 @@ int show_map(int pid)
pss += mi->pss;
size += mi->size;
- if(terse && !mi->private_dirty) continue;
+ if (terse && !mi->private_dirty) {
+ goto out;
+ }
- if(addresses) {
+ if (addresses) {
printf("%08x %08x %8d %8d %s\n", mi->start, mi->end,
mi->shared_clean + mi->shared_dirty,
mi->private_clean + mi->private_dirty,
@@ -187,8 +247,13 @@ int show_map(int pid)
mi->private_clean, mi->private_dirty,
mi->name);
}
+
+out:
+ mi = mi->next;
+ free(last);
}
- if(addresses) {
+
+ if (addresses) {
printf("-------- -------- -------- -------- ------------------------------\n");
printf(" %8d %8d TOTAL\n",
shared_dirty + shared_clean,
@@ -200,6 +265,7 @@ int show_map(int pid)
shared_clean, shared_dirty,
private_clean, private_dirty);
}
+
return 0;
}
@@ -207,16 +273,16 @@ int main(int argc, char *argv[])
{
int usage = 1;
- for(argc--, argv++; argc > 0; argc--, argv++) {
- if(!strcmp(argv[0],"-v")) {
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (!strcmp(argv[0],"-v")) {
verbose = 1;
continue;
}
- if(!strcmp(argv[0],"-t")) {
+ if (!strcmp(argv[0],"-t")) {
terse = 1;
continue;
}
- if(!strcmp(argv[0],"-a")) {
+ if (!strcmp(argv[0],"-a")) {
addresses = 1;
continue;
}
@@ -224,7 +290,7 @@ int main(int argc, char *argv[])
usage = 0;
}
- if(usage) {
+ if (usage) {
fprintf(stderr,
"showmap [-t] [-v] [-c] <pid>\n"
" -t = terse (show only items with private pages)\n"
@@ -233,5 +299,5 @@ int main(int argc, char *argv[])
);
}
- return 0;
+ return 0;
}