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@linaro.org Signed-off-by: Leo Yan leo.yan@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); }