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)