Skip to content

Commit

Permalink
kldxref: Refactor PNP entry parsing, no functional change
Browse files Browse the repository at this point in the history
- Add a free_pnp_list to complement parse_pnp_list.  Add freeing
  of 'new_desc' which was previously leaked.

- Move body of loop that checked a single pnp list element against a
  table entry into a parse_pnp_entry function to reduce indentation
  and split parse_entry into a smaller function.

- Similarly, split out a record_pnp_info function from parse_entry
  which builds the pnp_list and walks a table.

Reviewed by:	imp
Sponsored by:	DARPA
Differential Revision:	https://reviews.freebsd.org/D42965
  • Loading branch information
bsdjhb committed Dec 12, 2023
1 parent 4a3cf5f commit c40fa3d
Showing 1 changed file with 139 additions and 108 deletions.
247 changes: 139 additions & 108 deletions usr.sbin/kldxref/kldxref.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
size_t new_desc_size;
FILE *fp;

TAILQ_INIT(list);
walker = desc;
ep = desc + strlen(desc);
off = 0;
Expand Down Expand Up @@ -379,6 +380,142 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
errx(1, "Parse error of description string %s", desc);
}

static void
free_pnp_list(char *new_desc, pnp_list *list)
{
struct pnp_elt *elt, *elt_tmp;

TAILQ_FOREACH_SAFE(elt, list, next, elt_tmp) {
TAILQ_REMOVE(list, elt, next);
free(elt);
}
free(new_desc);
}

static void
parse_pnp_entry(struct elf_file *ef, struct pnp_elt *elt, const char *walker)
{
uint8_t v1;
uint16_t v2;
uint32_t v4;
int value;
char buffer[1024];

if (elt->pe_kind == TYPE_W32) {
memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
value = v4 & 0xffff;
record_int(value);
if (verbose > 1)
printf("W32:%#x", value);
value = (v4 >> 16) & 0xffff;
record_int(value);
if (verbose > 1)
printf(":%#x;", value);
} else if (elt->pe_kind & TYPE_INT) {
switch (elt->pe_kind & TYPE_SZ_MASK) {
case 1:
memcpy(&v1, walker + elt->pe_offset, sizeof(v1));
if ((elt->pe_kind & TYPE_FLAGGED) && v1 == 0xff)
value = -1;
else
value = v1;
break;
case 2:
memcpy(&v2, walker + elt->pe_offset, sizeof(v2));
if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff)
value = -1;
else
value = v2;
break;
case 4:
memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff)
value = -1;
else
value = v4;
break;
default:
errx(1, "Invalid size somehow %#x", elt->pe_kind);
}
if (verbose > 1)
printf("I:%#x;", value);
record_int(value);
} else if (elt->pe_kind == TYPE_T) {
/* Do nothing */
} else { /* E, Z or D -- P already filtered */
if (elt->pe_kind == TYPE_E) {
memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
strcpy(buffer, pnp_eisaformat(v4));
} else {
char *ptr;

ptr = *(char **)(walker + elt->pe_offset);
buffer[0] = '\0';
if (ptr != NULL) {
EF_SEG_READ_STRING(ef, (Elf_Off)ptr,
sizeof(buffer), buffer);
buffer[sizeof(buffer) - 1] = '\0';
}
}
if (verbose > 1)
printf("%c:%s;", elt->pe_kind == TYPE_E ? 'E' :
(elt->pe_kind == TYPE_Z ? 'Z' : 'D'), buffer);
record_string(buffer);
}
}

static void
record_pnp_info(struct elf_file *ef, const char *cval,
struct mod_pnp_match_info *pnp, const char *descr)
{
pnp_list list;
struct pnp_elt *elt;
char *new_descr, *walker;
void *table;
size_t len;
int error, i;

if (verbose > 1)
printf(" pnp info for bus %s format %s %d entries of %d bytes\n",
cval, descr, pnp->num_entry, pnp->entry_len);

/*
* Parse descr to weed out the chaff and to create a list
* of offsets to output.
*/
parse_pnp_list(descr, &new_descr, &list);
record_int(MDT_PNP_INFO);
record_string(cval);
record_string(new_descr);
record_int(pnp->num_entry);
len = pnp->num_entry * pnp->entry_len;
table = malloc(len);
error = EF_SEG_READ_REL(ef, (Elf_Off)pnp->table, len, table);
if (error != 0) {
free_pnp_list(new_descr, &list);
free(table);
return;
}

/*
* Walk the list and output things. We've collapsed all the
* variant forms of the table down to just ints and strings.
*/
walker = table;
for (i = 0; i < pnp->num_entry; i++) {
TAILQ_FOREACH(elt, &list, next) {
parse_pnp_entry(ef, elt, walker);
}
if (verbose > 1)
printf("\n");
walker += pnp->entry_len;
}

/* Now free it */
free_pnp_list(new_descr, &list);
free(table);
}

static int
parse_entry(struct mod_metadata *md, const char *cval,
struct elf_file *ef, const char *kldname)
Expand All @@ -388,10 +525,7 @@ parse_entry(struct mod_metadata *md, const char *cval,
struct mod_pnp_match_info pnp;
char descr[1024];
Elf_Off data;
int error, i;
size_t len;
char *walker;
void *table;
int error;

data = (Elf_Off)md->md_data;
error = 0;
Expand Down Expand Up @@ -432,110 +566,7 @@ parse_entry(struct mod_metadata *md, const char *cval,
printf(" pnp info for bus %s format %s %d entries of %d bytes\n",
cval, descr, pnp.num_entry, pnp.entry_len);
} else {
pnp_list list;
struct pnp_elt *elt, *elt_tmp;
char *new_descr;

if (verbose > 1)
printf(" pnp info for bus %s format %s %d entries of %d bytes\n",
cval, descr, pnp.num_entry, pnp.entry_len);
/*
* Parse descr to weed out the chaff and to create a list
* of offsets to output.
*/
TAILQ_INIT(&list);
parse_pnp_list(descr, &new_descr, &list);
record_int(MDT_PNP_INFO);
record_string(cval);
record_string(new_descr);
record_int(pnp.num_entry);
len = pnp.num_entry * pnp.entry_len;
walker = table = malloc(len);
check(EF_SEG_READ_REL(ef, (Elf_Off)pnp.table, len, table));

/*
* Walk the list and output things. We've collapsed all the
* variant forms of the table down to just ints and strings.
*/
for (i = 0; i < pnp.num_entry; i++) {
TAILQ_FOREACH(elt, &list, next) {
uint8_t v1;
uint16_t v2;
uint32_t v4;
int value;
char buffer[1024];

if (elt->pe_kind == TYPE_W32) {
memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
value = v4 & 0xffff;
record_int(value);
if (verbose > 1)
printf("W32:%#x", value);
value = (v4 >> 16) & 0xffff;
record_int(value);
if (verbose > 1)
printf(":%#x;", value);
} else if (elt->pe_kind & TYPE_INT) {
switch (elt->pe_kind & TYPE_SZ_MASK) {
case 1:
memcpy(&v1, walker + elt->pe_offset, sizeof(v1));
if ((elt->pe_kind & TYPE_FLAGGED) && v1 == 0xff)
value = -1;
else
value = v1;
break;
case 2:
memcpy(&v2, walker + elt->pe_offset, sizeof(v2));
if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff)
value = -1;
else
value = v2;
break;
case 4:
memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff)
value = -1;
else
value = v4;
break;
default:
errx(1, "Invalid size somehow %#x", elt->pe_kind);
}
if (verbose > 1)
printf("I:%#x;", value);
record_int(value);
} else if (elt->pe_kind == TYPE_T) {
/* Do nothing */
} else { /* E, Z or D -- P already filtered */
if (elt->pe_kind == TYPE_E) {
memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
strcpy(buffer, pnp_eisaformat(v4));
} else {
char *ptr;

ptr = *(char **)(walker + elt->pe_offset);
buffer[0] = '\0';
if (ptr != NULL) {
EF_SEG_READ_STRING(ef, (Elf_Off)ptr,
sizeof(buffer), buffer);
buffer[sizeof(buffer) - 1] = '\0';
}
}
if (verbose > 1)
printf("%c:%s;", elt->pe_kind == TYPE_E ? 'E' : (elt->pe_kind == TYPE_Z ? 'Z' : 'D'), buffer);
record_string(buffer);
}
}
if (verbose > 1)
printf("\n");
walker += pnp.entry_len;
}
/* Now free it */
TAILQ_FOREACH_SAFE(elt, &list, next, elt_tmp) {
TAILQ_REMOVE(&list, elt, next);
free(elt);
}
free(table);
record_pnp_info(ef, cval, &pnp, descr);
}
break;
default:
Expand Down

0 comments on commit c40fa3d

Please sign in to comment.