sorttable reads a list of functions from vmlinux, provided by the output of
nm, with the -S flag specified providing function sizes.
It does so using fscanf(fp, "%16s %16s %c %*s\n", ...) reading address,
size, type (a single character) and name.
However, nm outputs no size for a symbol which has none, meaning that it
misinterprets these entries - interpreting the type character as the size,
and, if the name is a single character, ignores the newline and swallows
the address of the next entry.
Size-less single character names exist (e.g. the assemblers' loop counters
left over as local absolute symbols):
0000000000000001 a i
000000000000000f a i
0000000000000050 a j
0000000000000052 a t
000000000000009f a i
0000000000000200 a i
sorttable is looking for functions and these are not that, and with nm's
output sorted, it just so happens to be that what's swallowed is never a
function.
However the next commit in this series stops sorting nm's output, so this
bug can results in function names being lost.
Fix the issue by using '%*[^\n]' in fscanf() rather than '%*s' such that
the scan cannot move past the newline.
Then, compare the address and size fields (which are always padded to the
same width if output by nm) - if they differ, then this is a misread, so
simply discard the entry.
It's fine to discard these, as sorttable's raison d'ĂȘtre is to discover
whether a call site is contained within a function and an empty function
can't contain anything.
Assisted-by: LLM
Signed-off-by: Lorenzo Stoakes (ARM) <[email protected]>
---
scripts/sorttable.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index d7b50581c732..88e49a5c4251 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -322,10 +322,23 @@ static int parse_symbols(const char *fname)
return -1;
}
- while (fscanf(fp, "%16s %16s %c %*s\n", addr_str, size_str, &type) ==
3) {
+ while (fscanf(fp, "%16s %16s %c%*[^\n]", addr_str, size_str, &type) ==
3) {
uint64_t addr;
uint64_t size;
+ /*
+ * nm outputs size-less entries with a missing 2nd value, which
+ * means fscanf() just misread its fields.
+ *
+ * These don't matter as a call site cannot be in an empty
+ * function, so just skip them.
+ *
+ * nm pads address and size to the same width, so if their
+ * widths differ, this is a misread.
+ */
+ if (strlen(size_str) != strlen(addr_str))
+ continue;
+
/* Only care about functions */
if (type != 't' && type != 'T' && type != 'W')
continue;
--
2.55.0