From: sashiko-bot@kernel.org
To: "Matt Turner" <mattst88@gmail.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH 3/5] alpha/perf: implement ProfileMe sampling
Date: Wed, 28 Oct 2026 18:28:48 +0000 [thread overview]
Message-ID: <sashiko-outbox-188288@kernel.org> (raw)
In-Reply-To: <20261028-alpha-profileme-v1-3-d44b52bf2500@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] alpha/perf: wrong register and stack state in alpha_perf_event_profileme()
--
commit 4ba1c82f19c556ae6c582ff386ff198b05c6a1eb
Author: Matt Turner <mattst88@gmail.com>
alpha/perf: implement ProfileMe sampling
This commit implements ProfileMe performance counter sampling on Alpha
EV67 and later processors, selecting it via the profileme config attribute
or precise_ip and attributing samples to the PC latched in PMPC.
> diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
> index 70840c05d39bf..24c96feda9424 100644
> --- a/arch/alpha/kernel/perf_event.c
> +++ b/arch/alpha/kernel/perf_event.c
[ ... ]
> @@ -832,6 +904,61 @@ void perf_event_print_debug(void)
> }
>
>
> +/*
> + * Handle the close of a ProfileMe window on PCTR0.
> + *
> + * PCTR0 stops counting when the window closes and does not start again
> + * until PCTR_CTL is written, so the status must be read first and the
> + * counters then rearmed unconditionally.
> + */
> +static void alpha_perf_event_profileme(struct perf_event *event,
> + struct hw_perf_event *hwc,
> + struct pt_regs *regs)
> +{
> + struct perf_sample_data data;
> + struct pt_regs pm_regs;
> + unsigned long i_stat, pmpc, ovr;
> +
> + i_stat = wrperfmon(PERFMON_CMD_I_STAT, 0);
> + pmpc = wrperfmon(PERFMON_CMD_PMPC, 0);
> +
> + alpha_perf_event_update(event, hwc, 0, alpha_pmu->pmc_max_period[0]+1);
> +
> + /*
> + * When PCTR0 counts instructions, up to 7 of them are counted after
> + * the overflow but before the window opens. I_STAT reports how many.
> + */
> + if (!(hwc->config_base & EV67_PCTR_PCTR0_CYCLES)) {
> + ovr = (i_stat >> EV67_I_STAT_OVR_SHIFT) & EV67_I_STAT_OVR_MASK;
> + local64_sub(ovr, &event->count);
> + local64_add(ovr, &hwc->period_left);
> + }
> +
> + /*
> + * Attribute the sample to the profiled instruction rather than to
> + * wherever the interrupt landed, including the user/kernel mode that
> + * perf derives from regs. A PALmode PMPC is a physical address that
> + * perf cannot resolve. That happens for ITB miss, Istream access
> + * violation and interrupt redirects, and for instructions inside
> + * PALcode. Keep the interrupted PC, which for redirects is the
> + * instruction that trapped.
> + */
> + pm_regs = *regs;
> + if (!(pmpc & EV67_PMPC_PAL)) {
> + pm_regs.pc = pmpc & EV67_PMPC_PC_MASK;
> + /* PS bit 3 is the mode bit that user_mode() tests. */
> + if (pm_regs.pc < TASK_SIZE)
> + pm_regs.ps |= 8UL;
> + else
> + pm_regs.ps &= ~8UL;
> + }
> +
> + perf_sample_data_init(&data, 0, hwc->last_period);
> +
> + if (alpha_perf_event_set_period(event, hwc, 0))
> + perf_event_overflow(event, &data, &pm_regs);
> +}
[Severity: High]
When a user-mode instruction is profiled (pm_regs.pc < TASK_SIZE), but the
PMI is delivered after the CPU has entered kernel mode (!user_mode(regs)),
regs is the kernel interrupt trap frame containing live kernel GPRs, while
the user task's registers live in task_pt_regs(current).
By copying *regs into pm_regs and setting pm_regs.ps |= 8UL before calling
perf_event_overflow(), user_mode(&pm_regs) evaluates to true in
kernel/events/core.c:perf_sample_regs_user():
if (user_mode(regs)) {
regs_user->abi = perf_reg_abi(current);
regs_user->regs = regs;
} else if (is_user_task(current)) {
perf_get_regs_user(regs_user, regs);
}
and in kernel/events/core.c:perf_sample_regs_intr():
if (exclude_kernel && !user_mode(regs)) {
regs_intr->abi = PERF_SAMPLE_REGS_ABI_NONE;
regs_intr->regs = NULL;
} else {
regs_intr->regs = regs;
regs_intr->abi = perf_reg_abi(current);
}
Doesn't this cause PERF_SAMPLE_REGS_USER and PERF_SAMPLE_REGS_INTR (even
when attr.exclude_kernel is set) to record live kernel registers from the
kernel interrupt trap frame into the user-visible perf ring buffer instead
of fetching task_pt_regs(current), while also corrupting user DWARF
callgraph unwinding?
Additionally, if current is a kernel thread when this happens,
perf_sample_regs_user() sets regs_user->regs = &pm_regs while
perf_sample_ustack_size() returns 0 (since current->mm is NULL), which
causes perf_prepare_sample() and perf_output_sample_ustack() to disagree
on the PERF_SAMPLE_STACK_USER record size.
Similarly, when !user_mode(&pm_regs) is true (pm_regs.pc >= TASK_SIZE),
passing the stack-local &pm_regs to perf_event_overflow() affects
arch/alpha/kernel/perf_regs.c:perf_reg_value():
if (idx == PERF_REG_ALPHA_SP) {
if (user_mode(regs))
return user_stack_pointer(regs);
if (!object_is_on_stack(regs))
return 0;
/* Same kernel sp approximation as stacktrace.c. */
return (unsigned long)(regs + 1);
}
and arch/alpha/kernel/stacktrace.c:arch_stack_walk():
if (regs && task == current) {
ksp = (unsigned long)(regs + 1);
}
Because pm_regs is a local variable on the stack, object_is_on_stack(&pm_regs)
is true, so &pm_regs + 1 points inside alpha_perf_event_profileme()'s own
stack frame rather than the end of the interrupted trap frame (regs + 1).
And if the PMI landed in user mode after a profiled kernel instruction,
clearing bit 3 of pm_regs.ps causes perf_callchain_kernel() and
PERF_SAMPLE_REGS_INTR to treat the user register frame as a kernel frame
and unwind the kernel stack starting from &pm_regs + 1.
Could the PC and PS adjustments be made in-place on regs (and restored
after perf_event_overflow()) only when the PMPC mode matches the
interrupted mode in regs, or how should mode-mismatched samples handle register
and stack sampling?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261028-alpha-profileme-v1-0-d44b52bf2500@gmail.com?part=3
next prev parent reply other threads:[~2026-10-28 18:28 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 18:09 [PATCH 0/5] alpha/perf: add ProfileMe sampling Matt Turner
2026-10-28 18:09 ` [PATCH 1/5] alpha/perf: pass PERFMON_CMD_LOGGING_ALL to the logging options call Matt Turner
2026-10-28 18:12 ` sashiko-bot
2026-10-29 17:38 ` Magnus Lindholm
2026-10-28 18:09 ` [PATCH 2/5] alpha/perf: add sysfs format and event attributes Matt Turner
2026-10-28 18:13 ` sashiko-bot
2026-10-28 18:09 ` [PATCH 3/5] alpha/perf: implement ProfileMe sampling Matt Turner
2026-10-28 18:28 ` sashiko-bot [this message]
2026-10-29 15:18 ` Magnus Lindholm
2026-10-28 18:09 ` [PATCH 4/5] alpha/perf: attach ProfileMe status as PERF_SAMPLE_RAW data Matt Turner
2026-10-28 18:26 ` sashiko-bot
2026-10-28 18:09 ` [PATCH 5/5] alpha/perf: optionally randomize the ProfileMe sampling interval Matt Turner
2026-10-28 18:21 ` sashiko-bot
2026-10-29 15:01 ` Magnus Lindholm
2026-10-29 9:11 ` [PATCH 0/5] alpha/perf: add ProfileMe sampling Peter Zijlstra
2026-10-29 15:34 ` Matt Turner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-188288@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mattst88@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox