pmap: fixing broken indentation in the -X/-XX modes

This commit changes the processing principle of the -X/-XX modes
from 1-pass to 2-pass. A separate width measurement stage has been
added, so that the real maximum widths can be measured and used
for correct indentation.

The firstmapping variable now has a new value (2) used for the
width measurement stage (1st pass). The printing is disabled
in this stage. The file position is reset to the beginning
of the file once the end of file is reached and the printing stage
(2nd pass) begins.
It's questionable if this approach is sensitive to Read-after-Write
race conditions. Anyway, this feature is a good candidate for
a complete redesign in the future.

Additionally this commit introduces a final cleaning of the list
used for the evaluation of totals in the -X/-XX modes.
This commit is contained in:
Jaromir Capik 2013-02-06 23:01:54 +01:00
parent ca76af22ca
commit 20ce346ebd

92
pmap.c
View File

@ -184,7 +184,7 @@ struct listnode {
struct listnode *next; struct listnode *next;
}; };
static struct listnode *listhead=NULL, *listtail=NULL; static struct listnode *listhead=NULL, *listtail=NULL, *listnode;
static int is_unimportant (char *s) static int is_unimportant (char *s)
@ -201,7 +201,6 @@ static int is_unimportant (char *s)
static void print_extended_maps (FILE *f) static void print_extended_maps (FILE *f)
{ {
struct listnode *listnode;
char flags[DETAIL_LENGTH], map_desc[128], char flags[DETAIL_LENGTH], map_desc[128],
detail_desc[DETAIL_LENGTH], value_str[NUM_LENGTH], detail_desc[DETAIL_LENGTH], value_str[NUM_LENGTH],
start[NUM_LENGTH], end[NUM_LENGTH], start[NUM_LENGTH], end[NUM_LENGTH],
@ -216,7 +215,7 @@ static void print_extended_maps (FILE *f)
char has_vmflags = 0; char has_vmflags = 0;
ret = fgets(mapbuf, sizeof mapbuf, f); ret = fgets(mapbuf, sizeof mapbuf, f);
firstmapping = 1; firstmapping = 2;
while (ret != NULL) { while (ret != NULL) {
/* === READ MAPPING === */ /* === READ MAPPING === */
map_desc[0] = '\0'; map_desc[0] = '\0';
@ -254,7 +253,7 @@ static void print_extended_maps (FILE *f)
goto loop_end; goto loop_end;
/* === CREATE LIST AND FILL description FIELD === */ /* === CREATE LIST AND FILL description FIELD === */
if (listnode == NULL) { if (listnode == NULL) {
assert(firstmapping == 1); assert(firstmapping == 2);
listnode = calloc(1, sizeof *listnode); listnode = calloc(1, sizeof *listnode);
if (listhead == NULL) { if (listhead == NULL) {
assert(listtail == NULL); assert(listtail == NULL);
@ -271,15 +270,14 @@ static void print_extended_maps (FILE *f)
listnode->max_width = 7; listnode->max_width = 7;
} else { } else {
/* === LIST EXISTS === */ /* === LIST EXISTS === */
if ((listnode == NULL) || if (strcmp(listnode->description, detail_desc) != 0)
(strcmp(listnode->description, detail_desc) != 0))
xerrx(EXIT_FAILURE, "ERROR: %s %s", xerrx(EXIT_FAILURE, "ERROR: %s %s",
_("inconsistent detail field in smaps file, line:\n"), _("inconsistent detail field in smaps file, line:\n"),
mapbuf); mapbuf);
} }
strcpy(listnode->value_str, value_str); strcpy(listnode->value_str, value_str);
sscanf(value_str, "%"KLF"u", &listnode->value); sscanf(value_str, "%"KLF"u", &listnode->value);
listnode->total += listnode->value; if (firstmapping == 2) listnode->total += listnode->value;
if (strlen(value_str) > listnode->max_width) if (strlen(value_str) > listnode->max_width)
listnode->max_width = strlen(value_str); listnode->max_width = strlen(value_str);
listnode = listnode->next; listnode = listnode->next;
@ -297,51 +295,60 @@ loop_end:
if (strlen(vmflags) > maxwv) maxwv = strlen(vmflags); if (strlen(vmflags) > maxwv) maxwv = strlen(vmflags);
} }
/* === PRINT THIS MAPPING === */ if (firstmapping == 2) { /* width measurement stage, do not print anything yet */
/* Print header */ if (ret == NULL) { /* once the end of file is reached ...*/
if (firstmapping && !q_option) { firstmapping = 1; /* ... we reset the file position to the beginning of the file */
if (strlen("Address") > maxw1) maxw1 = strlen("Address"); fseek(f, 0, SEEK_SET); /* ... and repeat the process with printing enabled */
if (strlen("Flags") > maxw2) maxw2 = strlen("Flags"); ret = fgets(mapbuf, sizeof mapbuf, f); /* this is not ideal and needs to be redesigned one day */
if (strlen("Offset") > maxw3) maxw3 = strlen("Offset"); }
if (strlen("Device") > maxw4) maxw4 = strlen("Device"); } else { /* the maximum widths have been measured, we've already reached the printing stage */
if (strlen("Inode") > maxw5) maxw5 = strlen("Inode"); /* === PRINT THIS MAPPING === */
if (has_vmflags && strlen("VmFlags") > maxwv) maxwv = strlen("VmFlags"); /* Print header */
if (firstmapping && !q_option) {
if (strlen("Address") > maxw1) maxw1 = strlen("Address");
if (strlen("Flags") > maxw2) maxw2 = strlen("Flags");
if (strlen("Offset") > maxw3) maxw3 = strlen("Offset");
if (strlen("Device") > maxw4) maxw4 = strlen("Device");
if (strlen("Inode") > maxw5) maxw5 = strlen("Inode");
if (has_vmflags && strlen("VmFlags") > maxwv) maxwv = strlen("VmFlags");
sprintf(fmt_str, "%%%ds %%%ds %%%ds %%%ds %%%ds",
maxw1, maxw2, maxw3, maxw4, maxw5);
printf(fmt_str, "Address", "Flags", "Offset", "Device", "Inode");
for (listnode=listhead; listnode=listnode->next;
listnode!=NULL) {
sprintf(fmt_str, " %%%ds", listnode->max_width);
printf(fmt_str, listnode->description);
}
if (has_vmflags) {
sprintf(fmt_str, " %%%ds", maxwv);
printf(fmt_str, "VmFlags");
}
printf(" %s\n", "Description");
}
/* Print data */
sprintf(fmt_str, "%%%ds %%%ds %%%ds %%%ds %%%ds", sprintf(fmt_str, "%%%ds %%%ds %%%ds %%%ds %%%ds",
maxw1, maxw2, maxw3, maxw4, maxw5); maxw1, maxw2, maxw3, maxw4, maxw5);
printf(fmt_str, "Address", "Flags", "Offset", "Device", "Inode"); printf(fmt_str, start, flags, offset, dev, inode);
for (listnode=listhead; listnode=listnode->next; for (listnode=listhead; listnode=listnode->next;
listnode!=NULL) { listnode!=NULL) {
sprintf(fmt_str, " %%%ds", listnode->max_width); sprintf(fmt_str, " %%%ds", listnode->max_width);
printf(fmt_str, listnode->description); printf(fmt_str, listnode->value_str);
} }
if (has_vmflags) { if (has_vmflags) {
sprintf(fmt_str, " %%%ds", maxwv); sprintf(fmt_str, " %%%ds", maxwv);
printf(fmt_str, "VmFlags"); printf(fmt_str, vmflags);
} }
printf(" %s\n", "Description"); printf(" %s\n", map_desc);
firstmapping = 0;
} }
/* Print data */
sprintf(fmt_str, "%%%ds %%%ds %%%ds %%%ds %%%ds",
maxw1, maxw2, maxw3, maxw4, maxw5);
printf(fmt_str, start, flags, offset, dev, inode);
for (listnode=listhead; listnode=listnode->next;
listnode!=NULL) {
sprintf(fmt_str, " %%%ds", listnode->max_width);
printf(fmt_str, listnode->value_str);
}
if (has_vmflags) {
sprintf(fmt_str, " %%%ds", maxwv);
printf(fmt_str, vmflags);
}
printf(" %s\n", map_desc);
firstmapping = 0;
} }
/* === PRINT TOTALS === */ /* === PRINT TOTALS === */
if (!q_option && listhead!=NULL) { if (!q_option && listhead!=NULL) {
@ -722,6 +729,13 @@ int main(int argc, char **argv)
closeproc(PT); closeproc(PT);
free(pidlist); free(pidlist);
/* cleaning the list used for the -X/-XX modes */
for (listnode = listhead; listnode != NULL ; ) {
listnode = listnode -> next;
free(listhead);
listhead = listnode;
}
if (count) if (count)
/* didn't find all processes asked for */ /* didn't find all processes asked for */
ret |= 42; ret |= 42;