diff options
Diffstat (limited to 'showmap')
-rw-r--r-- | showmap/showmap.c | 244 |
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; } |