[PATCH v2 09/14] perf cs-etm: Classify exception calls using the exception packet
James Clark
james.clark at linaro.org
Tue Sep 29 07:08:42 PDT 2026
On 23/09/2026 16:21, Leo Yan wrote:
> ETMv4 and ETE use the same exception number for SVC, HVC and SMC.
> Identify SVC by inspecting the instruction before the preferred return
> address in the exception packet.
>
> Preserve the exception level and preferred return address from OpenCSD,
> and use them with the packet's ISA in cs_etm__is_syscall() and
> cs_etm__is_sync_exception(). This makes exception call classification
> independent of the preceding instruction range.
>
> Assisted-by: Codex:gpt-6
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
> tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 7 ++++++-
> tools/perf/util/cs-etm.c | 10 +++-------
> tools/perf/util/cs-etm.h | 1 +
> 3 files changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> index 469aba5e596a791289c5bcece132aba7b0baf6c3..48e8c355a3e495cc30dcb4056c04a034d10ce860 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> @@ -511,7 +511,8 @@ cs_etm_decoder__buffer_exception(struct cs_etm_queue *etmq,
> struct cs_etm_packet_queue *queue,
> const ocsd_generic_trace_elem *elem,
> const uint8_t trace_chan_id)
> -{ int ret = 0;
> +{
> + int ret = 0;
> struct cs_etm_packet *packet;
>
> ret = cs_etm_decoder__buffer_packet(etmq, queue, elem, trace_chan_id,
> @@ -521,6 +522,10 @@ cs_etm_decoder__buffer_exception(struct cs_etm_queue *etmq,
>
> packet = &queue->packet_buffer[queue->tail];
> packet->exception_number = elem->exception_number;
> + if (elem->context.el_valid)
> + packet->el = elem->context.exception_level;
> + if (elem->excep_ret_addr)
> + packet->end_addr = elem->en_addr;
>
> return ret;
> }
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index c8a92b5dba6001329d68766d540b9b7ead90e9e6..a40b3b2fe2e6318154111d9b7ebd05bee53934f1 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -2019,7 +2019,7 @@ static int cs_etm__exception(struct cs_etm_traceid_queue *tidq)
> * to generate branch sample for the instruction range before the
> * exception is trapped to kernel or before the exception returning.
> *
> - * The exception packet includes the dummy address values, so don't
> + * The exception packet does not describe an instruction range, so don't
> * swap PACKET with PREV_PACKET. This keeps PREV_PACKET to be useful
> * for generating instruction and branch samples.
> */
> @@ -2225,7 +2225,6 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
> struct cs_etm_traceid_queue *tidq, u64 magic)
> {
> struct cs_etm_packet *packet = tidq->packet;
> - struct cs_etm_packet *prev_packet = tidq->prev_packet;
>
> if (magic == __perf_cs_etmv3_magic)
> if (packet->exception_number == CS_ETMV3_EXC_SVC)
> @@ -2238,8 +2237,7 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
> */
> if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) {
> if (packet->exception_number == CS_ETMV4_EXC_CALL &&
> - cs_etm__is_svc_instr(etmq, tidq, prev_packet,
> - prev_packet->end_addr))
> + cs_etm__is_svc_instr(etmq, tidq, packet, packet->end_addr))
> return true;
> }
>
> @@ -2277,7 +2275,6 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
> u64 magic)
> {
> struct cs_etm_packet *packet = tidq->packet;
> - struct cs_etm_packet *prev_packet = tidq->prev_packet;
>
> if (magic == __perf_cs_etmv3_magic)
> if (packet->exception_number == CS_ETMV3_EXC_SMC ||
> @@ -2301,8 +2298,7 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
> * (SMC, HVC) are taken as sync exceptions.
> */
> if (packet->exception_number == CS_ETMV4_EXC_CALL &&
> - !cs_etm__is_svc_instr(etmq, tidq, prev_packet,
> - prev_packet->end_addr))
> + !cs_etm__is_svc_instr(etmq, tidq, packet, packet->end_addr))
> return true;
>
> /*
> diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
> index b81099c2b301c25f894cc9a50edfde87aceff49d..4d03f2a680b58aacd91c9f6c957fb2d38e7ac2ad 100644
> --- a/tools/perf/util/cs-etm.h
> +++ b/tools/perf/util/cs-etm.h
> @@ -174,6 +174,7 @@ struct cs_etm_packet {
> enum cs_etm_sample_type sample_type;
> enum cs_etm_isa isa;
> u64 start_addr;
> + /* For exceptions: preferred return address, or CS_ETM_INVAL_ADDR. */
> u64 end_addr;
Minor nit, but you could use a union. I don't know how clear re-using
"end_addr" id for exception packets is when reading the code.
union {
u64 end_addr; // Range packets
u64 pref_ret_addr; // Exception packets
};
> u32 instr_count;
> u32 last_instr_type;
>
More information about the linux-arm-kernel
mailing list