[PATCH v3 05/14] perf cs-etm: Use the recorded instruction size for A32 and A64

Leo Yan leo.yan at arm.com
Fri Oct 30 08:13:12 PDT 2026


Use packet->last_instr_size in cs_etm__instr_size() instead of a
hard-coded value of four. Ordinary A32/A64 instruction ranges are
unchanged, since their instructions are always four bytes.

Prepare for synthesizing exception entries separately from the preceding
instruction range. An exception packet may have last_instr_size = 0,
meaning that no instruction completed at the exception source PC and the
exception return address must not advance past that PC. The thread stack
computes the return address as the source PC plus the instruction size,
so returning four would incorrectly advance the return address by four
bytes.

Keep per-address decoding for T32. A range can mix 16-bit and 32-bit
instructions, so last_instr_size describes only the final instruction
and cannot determine the size at an arbitrary address in the range.

Reviewed-by: James Clark <james.clark at linaro.org>
Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 tools/perf/util/cs-etm.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index bdcf9481312943b2bbcade8f9688311853c138f2..9126f6327e98b67852b6a55980d67abb24de17fe 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -1391,8 +1391,7 @@ static inline int cs_etm__instr_size(struct cs_etm_queue *etmq,
 	if (packet->isa == CS_ETM_ISA_T32)
 		return cs_etm__t32_instr_size(etmq, tidq, packet, addr);
 
-	/* Otherwise, 4-byte instruction size for A32/A64 */
-	return 4;
+	return packet->last_instr_size;
 }
 
 static inline u64 cs_etm__first_executed_instr(struct cs_etm_packet *packet)
@@ -1572,6 +1571,15 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
 
 	sample->insn_len = cs_etm__instr_size(etmq, tidq, packet, sample->ip);
 
+	/*
+	 * The instruction length should always fit within sample->insn,
+	 * but check it to prevent an out-of-bounds write.
+	 */
+	if (sample->insn_len > sizeof(sample->insn)) {
+		sample->insn_len = 0;
+		return;
+	}
+
 	cs_etm__frontend_mem_access(etmq, tidq, packet, sample->ip,
 				    sample->insn_len, (void *)sample->insn);
 }

-- 
2.34.1




More information about the linux-arm-kernel mailing list