[Crash-utility] [PATCH 11/16] MIPS64: Fixes for the gathering of the active task registers for the 'bt' command

Youling Tang tangyouling at loongson.cn
Wed Mar 10 09:21:29 UTC 2021


On 03/10/2021 09:19 AM, HAGIO KAZUHITO(萩尾 一仁) wrote:
> -----Original Message-----
>> dumpfiles:
>>   (1) If ELF notes are not available, read them from the kernel's
>>       crash_notes.
> This is reverse?  i.e. If kernel's crash_notes are not available,
> read them from ELF notes.
Yes, If crash_notes is available, crash_notes will be used first, otherwise
it will be read from ELF notes.

Thanks,
Youling
> Thanks,
> Kazu
>
>>   (2) If an online CPUs did not save its ELF notes, then adjust
>>       the mapping of each ELF note to its CPU accordingly.
>>
>> E.g. With this patch:
>> crash> bt
>> PID: 4768   TASK: 9800000243bcf200  CPU: 3   COMMAND: "bash"
>>   #0 [980000024291f930] __crash_kexec at ffffffff802fff84
>>   #1 [980000024291faa0] panic at ffffffff80248cac
>>   #2 [980000024291fb40] die at ffffffff8021b338
>>   #3 [980000024291fb70] do_page_fault at ffffffff802315e0
>>   #4 [980000024291fbd0] tlb_do_page_fault_1 at ffffffff80239388
>>   #5 [980000024291fd00] sysrq_handle_crash at ffffffff8085d308
>>   #6 [980000024291fd10] __handle_sysrq at ffffffff8085d9e0
>>   #7 [980000024291fd60] write_sysrq_trigger at ffffffff8085e020
>>   #8 [980000024291fd80] proc_reg_write at ffffffff804762f0
>>   #9 [980000024291fda0] __vfs_write at ffffffff803f3138
>>
>> Signed-off-by: Huacai Chen <chenhuacai at loongson.cn>
>> Signed-off-by: Youling Tang <tangyouling at loongson.cn>
>> ---
>>   mips64.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 202 insertions(+), 1 deletion(-)
>>
>> diff --git a/mips64.c b/mips64.c
>> index 57a7f41..d949af4 100644
>> --- a/mips64.c
>> +++ b/mips64.c
>> @@ -42,7 +42,9 @@ static void mips64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
>>   static int mips64_get_dumpfile_stack_frame(struct bt_info *bt,
>>   			ulong *nip, ulong *ksp);
>>   static int mips64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
>> -
>> +static int mips64_init_active_task_regs(void);
>> +static int mips64_get_crash_notes(void);
>> +static int mips64_get_elf_notes(void);
>>
>>   /*
>>    * 3 Levels paging       PAGE_SIZE=16KB
>> @@ -806,6 +808,192 @@ mips64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
>>   	return TRUE;
>>   }
>>
>> +static int
>> +mips64_init_active_task_regs(void)
>> +{
>> +	int retval;
>> +
>> +	retval = mips64_get_crash_notes();
>> +	if (retval == TRUE)
>> +		return retval;
>> +
>> +	return mips64_get_elf_notes();
>> +}
>> +
>> +/*
>> + * Retrieve task registers for the time of the crash.
>> + */
>> +static int
>> +mips64_get_crash_notes(void)
>> +{
>> +	struct machine_specific *ms = machdep->machspec;
>> +	ulong crash_notes;
>> +	Elf64_Nhdr *note;
>> +	ulong offset;
>> +	char *buf, *p;
>> +	ulong *notes_ptrs;
>> +	ulong i;
>> +
>> +	/*
>> +	 * crash_notes contains per cpu memory for storing cpu states
>> +	 * in case of system crash.
>> +	 */
>> +	if (!symbol_exists("crash_notes"))
>> +		return FALSE;
>> +
>> +	crash_notes = symbol_value("crash_notes");
>> +
>> +	notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0]));
>> +
>> +	/*
>> +	 * Read crash_notes for the first CPU. crash_notes are in standard ELF
>> +	 * note format.
>> +	 */
>> +	if (!readmem(crash_notes, KVADDR, &notes_ptrs[kt->cpus-1],
>> +	    sizeof(notes_ptrs[kt->cpus-1]), "crash_notes",
>> +		     RETURN_ON_ERROR)) {
>> +		error(WARNING, "cannot read crash_notes\n");
>> +		FREEBUF(notes_ptrs);
>> +		return FALSE;
>> +	}
>> +
>> +	if (symbol_exists("__per_cpu_offset")) {
>> +
>> +		/*
>> +		 * Add __per_cpu_offset for each cpu to form the pointer to the notes
>> +		 */
>> +		for (i = 0; i < kt->cpus; i++)
>> +			notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
>> +	}
>> +
>> +	buf = GETBUF(SIZE(note_buf));
>> +
>> +	if (!(panic_task_regs = calloc((size_t)kt->cpus, sizeof(*panic_task_regs))))
>> +		error(FATAL, "cannot calloc panic_task_regs space\n");
>> +
>> +	for (i = 0; i < kt->cpus; i++) {
>> +
>> +		if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t",
>> +			     RETURN_ON_ERROR)) {
>> +			error(WARNING,
>> +				"cannot find NT_PRSTATUS note for cpu: %d\n", i);
>> +			goto fail;
>> +		}
>> +
>> +		/*
>> +		 * Do some sanity checks for this note before reading registers from it.
>> +		 */
>> +		note = (Elf64_Nhdr *)buf;
>> +		p = buf + sizeof(Elf64_Nhdr);
>> +
>> +		/*
>> +		 * dumpfiles created with qemu won't have crash_notes, but there will
>> +		 * be elf notes; dumpfiles created by kdump do not create notes for
>> +		 * offline cpus.
>> +		 */
>> +		if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) {
>> +			if (DISKDUMP_DUMPFILE())
>> +				note = diskdump_get_prstatus_percpu(i);
>> +			else if (KDUMP_DUMPFILE())
>> +				note = netdump_get_prstatus_percpu(i);
>> +			if (note) {
>> +				/*
>> +				 * SIZE(note_buf) accounts for a "final note", which is a
>> +				 * trailing empty elf note header.
>> +				 */
>> +				long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr);
>> +
>> +				if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) +
>> +				    note->n_descsz == notesz)
>> +					BCOPY((char *)note, buf, notesz);
>> +			} else {
>> +				error(WARNING,
>> +					"cannot find NT_PRSTATUS note for cpu: %d\n", i);
>> +				continue;
>> +			}
>> +		}
>> +
>> +		/*
>> +		 * Check the sanity of NT_PRSTATUS note only for each online cpu.
>> +		 */
>> +		if (note->n_type != NT_PRSTATUS) {
>> +			error(WARNING, "invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)\n");
>> +			goto fail;
>> +		}
>> +		if (!STRNEQ(p, "CORE")) {
>> +			error(WARNING, "invalid NT_PRSTATUS note (name != \"CORE\"\n");
>> +			goto fail;
>> +		}
>> +
>> +		/*
>> +		 * Find correct location of note data. This contains elf_prstatus
>> +		 * structure which has registers etc. for the crashed task.
>> +		 */
>> +		offset = sizeof(Elf64_Nhdr);
>> +		offset = roundup(offset + note->n_namesz, 4);
>> +		p = buf + offset; /* start of elf_prstatus */
>> +
>> +		BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i],
>> +		      sizeof(panic_task_regs[i]));
>> +	}
>> +
>> +	/*
>> +	 * And finally we have the registers for the crashed task. This is
>> +	 * used later on when dumping backtrace.
>> +	 */
>> +	ms->crash_task_regs = panic_task_regs;
>> +
>> +	FREEBUF(buf);
>> +	FREEBUF(notes_ptrs);
>> +	return TRUE;
>> +
>> +fail:
>> +	FREEBUF(buf);
>> +	FREEBUF(notes_ptrs);
>> +	free(panic_task_regs);
>> +	return FALSE;
>> +}
>> +
>> +static int
>> +mips64_get_elf_notes(void)
>> +{
>> +	struct machine_specific *ms = machdep->machspec;
>> +	int i;
>> +
>> +	if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE())
>> +		return FALSE;
>> +
>> +	panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs));
>> +	if (!panic_task_regs)
>> +		error(FATAL, "cannot calloc panic_task_regs space\n");
>> +
>> +	for (i = 0; i < kt->cpus; i++) {
>> +		Elf64_Nhdr *note = NULL;
>> +		size_t len;
>> +
>> +		if (DISKDUMP_DUMPFILE())
>> +			note = diskdump_get_prstatus_percpu(i);
>> +		else if (KDUMP_DUMPFILE())
>> +			note = netdump_get_prstatus_percpu(i);
>> +
>> +		if (!note) {
>> +			error(WARNING,
>> +			      "cannot find NT_PRSTATUS note for cpu: %d\n", i);
>> +			continue;
>> +		}
>> +
>> +		len = sizeof(Elf64_Nhdr);
>> +		len = roundup(len + note->n_namesz, 4);
>> +
>> +		BCOPY((char *)note + len + OFFSET(elf_prstatus_pr_reg),
>> +		      &panic_task_regs[i], sizeof(panic_task_regs[i]));
>> +	}
>> +
>> +	ms->crash_task_regs = panic_task_regs;
>> +
>> +	return TRUE;
>> +}
>> +
>>   /*
>>    * Accept or reject a symbol from the kernel namelist.
>>    */
>> @@ -959,9 +1147,22 @@ mips64_init(int when)
>>   		mips64_stackframe_init();
>>   		if (!machdep->hz)
>>   			machdep->hz = 250;
>> +		MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus",
>> +				   "pr_reg");
>> +		STRUCT_SIZE_INIT(note_buf, "note_buf_t");
>>   		break;
>>
>>   	case POST_VM:
>> +		/*
>> +		 * crash_notes contains machine specific information about the
>> +		 * crash. In particular, it contains CPU registers at the time
>> +		 * of the crash. We need this information to extract correct
>> +		 * backtraces from the panic task.
>> +		 */
>> +		if (!ACTIVE() && !mips64_init_active_task_regs())
>> +			error(WARNING,
>> +			    "cannot retrieve registers for active task%s\n\n",
>> +				kt->cpus > 1 ? "s" : "");
>>   		break;
>>   	}
>>   }
>> --
>> 2.1.0




More information about the Crash-utility mailing list