Hi,
On 11/5/26 9:10 PM, Pu Hu wrote:
From: Pu Hu <hupu(a)transsion.com>
note_buf_t is a typedef of a u32 array. Clang often omits it from
vmlinux DWARF even when the crash_notes symbol is present.
SIZE(note_buf) then aborts session startup:
crash: invalid structure size: note_buf
FILE: arm64.c FUNCTION: arm64_get_crash_notes()
Look up note_buf_t first and note_buf second. When neither type is
available, measure one NT_PRSTATUS note from the per-cpu crash note
in memory and include the terminating empty Elf note header. The
length stays local to arm64_get_crash_notes() and is not written into
size_table. If it still cannot be determined, warn and continue so a
raw RAM dump can be opened.
A vmlinux that already contains note_buf_t keeps the previous size.
No constant note length is introduced.
I wonder if this is a general issue or arm64 specific, in this old thread something is
done in task_init()
Can it be done as a general thing instead of arm64 only?
https://lists.crash-utility.osci.io/archives/list/devel@lists.crash-utili...
Kazu, you reviewed the old patch from Lianbo for ppc64, any idea about above?
Signed-off-by: Pu Hu <hupu(a)transsion.com>
---
arm64.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 86 insertions(+), 4 deletions(-)
diff --git a/arm64.c b/arm64.c
index 39f745b..4f0b621
--- a/arm64.c
+++ b/arm64.c
@@ -2788,6 +2788,8 @@ arm64_stackframe_init(void)
struct syment *sp1, *sp1n, *sp2, *sp2n, *sp3, *sp3n;
STRUCT_SIZE_INIT(note_buf, "note_buf_t");
+ if (INVALID_SIZE(note_buf))
+ STRUCT_SIZE_INIT(note_buf, "note_buf");
STRUCT_SIZE_INIT(elf_prstatus, "elf_prstatus");
MEMBER_OFFSET_INIT(elf_prstatus_pr_pid, "elf_prstatus", "pr_pid");
MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg");
@@ -5053,6 +5055,78 @@ arm64_get_smp_cpus(void)
}
+/*
+ * Bytes described by one Elf note header: header + aligned name + descriptor.
+ * Returns 0 when the header cannot be a crash NT_PRSTATUS note.
+ */
+static long
+arm64_note_size_from_mem(ulong addr)
+{
+ Elf64_Nhdr hdr;
+ long size, limit;
+
+ if (!addr)
+ return 0;
+
+ if (!readmem(addr, KVADDR, &hdr, sizeof(hdr),
+ "Elf64_Nhdr", RETURN_ON_ERROR|QUIET))
+ return 0;
+
+ /*
+ * A corrupt header must not become an allocation size.
+ * NT_PRSTATUS names are short; one elf_prstatus fits in a page.
+ */
+ limit = PAGESIZE() ? PAGESIZE() : 4096;
+ if (hdr.n_type != NT_PRSTATUS)
+ return 0;
+ if (!hdr.n_namesz || hdr.n_namesz > 256)
+ return 0;
+ if (!hdr.n_descsz || hdr.n_descsz > limit)
+ return 0;
+
+ size = sizeof(hdr);
+ size = roundup(size + hdr.n_namesz, 4);
+ size += hdr.n_descsz;
+ size = roundup(size, 4);
+ /* note_buf_t also contains the terminating empty note */
+ size += sizeof(hdr);
+ return size;
+}
+
+/*
+ * Bytes to read from one per-cpu crash note.
+ *
+ * Use the vmlinux type when it exists. note_buf_t is a typedef of a u32
+ * array and Clang often omits it from DWARF, so SIZE(note_buf) would
+ * abort startup. In that case measure the NT_PRSTATUS note that is
+ * actually stored. The result is local to arm64_get_crash_notes() and
+ * is not written back to size_table.
+ *
+ * Returns a positive size, or 0 if it cannot be determined.
+ */
+static long
+arm64_crash_note_size(ulong *notes_ptrs)
+{
+ long sz;
+ ulong i;
+
+ if (VALID_SIZE(note_buf) && size_table.note_buf > 0)
+ return size_table.note_buf;
+
+ if (!notes_ptrs)
+ return 0;
+
+ for (i = 0; i < kt->cpus; i++) {
+ sz = arm64_note_size_from_mem(notes_ptrs[i]);
+ if (sz > 0) {
+ if (CRASHDEBUG(1))
+ fprintf(fp, "arm64_crash_note_size: %ld\n", sz);
+ return sz;
+ }
+ }
+ return 0;
+}
+
/*
* Retrieve task registers for the time of the crash.
*/
@@ -5066,6 +5140,7 @@ arm64_get_crash_notes(void)
char *buf, *p;
ulong *notes_ptrs;
ulong i, found;
+ long note_sz;
if (!symbol_exists("crash_notes")) {
if (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE()) {
@@ -5127,13 +5202,20 @@ arm64_get_crash_notes(void)
notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
}
- buf = GETBUF(SIZE(note_buf));
+ note_sz = arm64_crash_note_size(notes_ptrs);
+ if (note_sz <= 0) {
+ error(WARNING, "cannot determine size of note_buf_t\n");
+ FREEBUF(notes_ptrs);
+ return;
+ }
+
+ buf = GETBUF(note_sz);
if (!(ms->panic_task_regs = calloc((size_t)kt->cpus, sizeof(struct
arm64_pt_regs))))
error(FATAL, "cannot calloc panic_task_regs space\n");
for (i = found = 0; i < kt->cpus; i++) {
- if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf),
+ if (!readmem(notes_ptrs[i], KVADDR, buf, note_sz,
"note_buf_t", RETURN_ON_ERROR)) {
error(WARNING, "cpu %d: cannot read NT_PRSTATUS note\n", i);
continue;
@@ -5157,10 +5239,10 @@ arm64_get_crash_notes(void)
note = netdump_get_prstatus_percpu(i);
if (note) {
/*
- * SIZE(note_buf) accounts for a "final note", which is a
+ * note_sz accounts for a "final note", which is a
* trailing empty elf note header.
*/
- long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr);
+ long notesz = note_sz - sizeof(Elf64_Nhdr);
if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) +
note->n_descsz == notesz)
--
Thanks
Rui (AKA. Dave Young)