Messages in this thread | | | Date | Wed, 23 Jan 2019 14:39:06 -0700 | From | Mathieu Poirier <> | Subject | Re: [PATCH v6 7/8] perf cs-etm: Set sample flags for exception packet |
| |
On Sat, Jan 19, 2019 at 09:43:46AM +0800, Leo Yan wrote: > The exception taken and returning are typical flow for instruction jump > but it needs to be handled with exception packets. This patch is to set > sample flags for exception packet. > > Since the exception packet contains the exception number, according to > the exception number this patch makes decision for belonging to which > exception types. > > The decoder have defined different exception number for ETMv3 and ETMv4 > separately, hence this patch needs firstly decide the ETM version by > using the metadata magic number, and this patch adds helper function > cs_etm__get_magic() for easily getting magic number. > > Based on different ETM version, the exception packet contains the > exception number, according to the exception number this patch makes > decision for the exception belonging to which exception types. > > In this patch, it introduces helper function cs_etm__is_svc_instr(); > for ETMv4 CS_ETMV4_EXC_CALL covers SVC, SMC and HVC cases in the > single exception number, thus need to use cs_etm__is_svc_instr() to > decide an exception taken for system call. > > Reviewed-by: Robert Walker <robert.walker@arm.com> > Signed-off-by: Leo Yan <leo.yan@linaro.org>
This is the other way around, i.e you wrote the code and then Robert reviewed it. With this change:
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> --- > tools/perf/util/cs-etm.c | 215 +++++++++++++++++++++++++++++++++++++++ > tools/perf/util/cs-etm.h | 44 ++++++++ > 2 files changed, 259 insertions(+) > > diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c > index e89989fe0a5c..052805de6513 100644 > --- a/tools/perf/util/cs-etm.c > +++ b/tools/perf/util/cs-etm.c > @@ -97,6 +97,20 @@ static u32 cs_etm__get_v7_protocol_version(u32 etmidr) > return CS_ETM_PROTO_ETMV3; > } > > +static int cs_etm__get_magic(u8 trace_chan_id, u64 *magic) > +{ > + struct int_node *inode; > + u64 *metadata; > + > + inode = intlist__find(traceid_list, trace_chan_id); > + if (!inode) > + return -EINVAL; > + > + metadata = inode->priv; > + *magic = metadata[CS_ETM_MAGIC]; > + return 0; > +} > + > int cs_etm__get_cpu(u8 trace_chan_id, int *cpu) > { > struct int_node *inode; > @@ -1122,10 +1136,174 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq) > return 0; > } > > +static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, > + struct cs_etm_packet *packet, > + u64 end_addr) > +{ > + u16 instr16; > + u32 instr32; > + u64 addr; > + > + switch (packet->isa) { > + case CS_ETM_ISA_T32: > + /* > + * The SVC of T32 is defined in ARM DDI 0487D.a, F5.1.247: > + * > + * b'15 b'8 > + * +-----------------+--------+ > + * | 1 1 0 1 1 1 1 1 | imm8 | > + * +-----------------+--------+ > + * > + * According to the specifiction, it only defines SVC for T32 > + * with 16 bits instruction and has no definition for 32bits; > + * so below only read 2 bytes as instruction size for T32. > + */ > + addr = end_addr - 2; > + cs_etm__mem_access(etmq, addr, sizeof(instr16), (u8 *)&instr16); > + if ((instr16 & 0xFF00) == 0xDF00) > + return true; > + > + break; > + case CS_ETM_ISA_A32: > + /* > + * The SVC of A32 is defined in ARM DDI 0487D.a, F5.1.247: > + * > + * b'31 b'28 b'27 b'24 > + * +---------+---------+-------------------------+ > + * | !1111 | 1 1 1 1 | imm24 | > + * +---------+---------+-------------------------+ > + */ > + addr = end_addr - 4; > + cs_etm__mem_access(etmq, addr, sizeof(instr32), (u8 *)&instr32); > + if ((instr32 & 0x0F000000) == 0x0F000000 && > + (instr32 & 0xF0000000) != 0xF0000000) > + return true; > + > + break; > + case CS_ETM_ISA_A64: > + /* > + * The SVC of A64 is defined in ARM DDI 0487D.a, C6.2.294: > + * > + * b'31 b'21 b'4 b'0 > + * +-----------------------+---------+-----------+ > + * | 1 1 0 1 0 1 0 0 0 0 0 | imm16 | 0 0 0 0 1 | > + * +-----------------------+---------+-----------+ > + */ > + addr = end_addr - 4; > + cs_etm__mem_access(etmq, addr, sizeof(instr32), (u8 *)&instr32); > + if ((instr32 & 0xFFE0001F) == 0xd4000001) > + return true; > + > + break; > + case CS_ETM_ISA_UNKNOWN: > + default: > + break; > + } > + > + return false; > +} > + > +static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, u64 magic) > +{ > + struct cs_etm_packet *packet = etmq->packet; > + struct cs_etm_packet *prev_packet = etmq->prev_packet; > + > + if (magic == __perf_cs_etmv3_magic) > + if (packet->exception_number == CS_ETMV3_EXC_SVC) > + return true; > + > + /* > + * ETMv4 exception type CS_ETMV4_EXC_CALL covers SVC, SMC and > + * HVC cases; need to check if it's SVC instruction based on > + * packet address. > + */ > + if (magic == __perf_cs_etmv4_magic) { > + if (packet->exception_number == CS_ETMV4_EXC_CALL && > + cs_etm__is_svc_instr(etmq, prev_packet, > + prev_packet->end_addr)) > + return true; > + } > + > + return false; > +} > + > +static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq, u64 magic) > +{ > + struct cs_etm_packet *packet = etmq->packet; > + > + if (magic == __perf_cs_etmv3_magic) > + if (packet->exception_number == CS_ETMV3_EXC_DEBUG_HALT || > + packet->exception_number == CS_ETMV3_EXC_ASYNC_DATA_ABORT || > + packet->exception_number == CS_ETMV3_EXC_PE_RESET || > + packet->exception_number == CS_ETMV3_EXC_IRQ || > + packet->exception_number == CS_ETMV3_EXC_FIQ) > + return true; > + > + if (magic == __perf_cs_etmv4_magic) > + if (packet->exception_number == CS_ETMV4_EXC_RESET || > + packet->exception_number == CS_ETMV4_EXC_DEBUG_HALT || > + packet->exception_number == CS_ETMV4_EXC_SYSTEM_ERROR || > + packet->exception_number == CS_ETMV4_EXC_INST_DEBUG || > + packet->exception_number == CS_ETMV4_EXC_DATA_DEBUG || > + packet->exception_number == CS_ETMV4_EXC_IRQ || > + packet->exception_number == CS_ETMV4_EXC_FIQ) > + return true; > + > + return false; > +} > + > +static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, u64 magic) > +{ > + struct cs_etm_packet *packet = etmq->packet; > + struct cs_etm_packet *prev_packet = etmq->prev_packet; > + > + if (magic == __perf_cs_etmv3_magic) > + if (packet->exception_number == CS_ETMV3_EXC_SMC || > + packet->exception_number == CS_ETMV3_EXC_HYP || > + packet->exception_number == CS_ETMV3_EXC_JAZELLE_THUMBEE || > + packet->exception_number == CS_ETMV3_EXC_UNDEFINED_INSTR || > + packet->exception_number == CS_ETMV3_EXC_PREFETCH_ABORT || > + packet->exception_number == CS_ETMV3_EXC_DATA_FAULT || > + packet->exception_number == CS_ETMV3_EXC_GENERIC) > + return true; > + > + if (magic == __perf_cs_etmv4_magic) { > + if (packet->exception_number == CS_ETMV4_EXC_TRAP || > + packet->exception_number == CS_ETMV4_EXC_ALIGNMENT || > + packet->exception_number == CS_ETMV4_EXC_INST_FAULT || > + packet->exception_number == CS_ETMV4_EXC_DATA_FAULT) > + return true; > + > + /* > + * For CS_ETMV4_EXC_CALL, except SVC other instructions > + * (SMC, HVC) are taken as sync exceptions. > + */ > + if (packet->exception_number == CS_ETMV4_EXC_CALL && > + !cs_etm__is_svc_instr(etmq, prev_packet, > + prev_packet->end_addr)) > + return true; > + > + /* > + * ETMv4 has 5 bits for exception number; if the numbers > + * are in the range ( CS_ETMV4_EXC_FIQ, CS_ETMV4_EXC_END ] > + * they are implementation defined exceptions. > + * > + * For this case, simply take it as sync exception. > + */ > + if (packet->exception_number > CS_ETMV4_EXC_FIQ && > + packet->exception_number <= CS_ETMV4_EXC_END) > + return true; > + } > + > + return false; > +} > + > static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq) > { > struct cs_etm_packet *packet = etmq->packet; > struct cs_etm_packet *prev_packet = etmq->prev_packet; > + u64 magic; > + int ret; > > switch (packet->sample_type) { > case CS_ETM_RANGE: > @@ -1206,6 +1384,43 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq) > PERF_IP_FLAG_TRACE_END; > break; > case CS_ETM_EXCEPTION: > + ret = cs_etm__get_magic(packet->trace_chan_id, &magic); > + if (ret) > + return ret; > + > + /* The exception is for system call. */ > + if (cs_etm__is_syscall(etmq, magic)) > + packet->flags = PERF_IP_FLAG_BRANCH | > + PERF_IP_FLAG_CALL | > + PERF_IP_FLAG_SYSCALLRET; > + /* > + * The exceptions are triggered by external signals from bus, > + * interrupt controller, debug module, PE reset or halt. > + */ > + else if (cs_etm__is_async_exception(etmq, magic)) > + packet->flags = PERF_IP_FLAG_BRANCH | > + PERF_IP_FLAG_CALL | > + PERF_IP_FLAG_ASYNC | > + PERF_IP_FLAG_INTERRUPT; > + /* > + * Otherwise, exception is caused by trap, instruction & > + * data fault, or alignment errors. > + */ > + else if (cs_etm__is_sync_exception(etmq, magic)) > + packet->flags = PERF_IP_FLAG_BRANCH | > + PERF_IP_FLAG_CALL | > + PERF_IP_FLAG_INTERRUPT; > + > + /* > + * When the exception packet is inserted, since exception > + * packet is not used standalone for generating samples > + * and it's affiliation to the previous instruction range > + * packet; so set previous range packet flags to tell perf > + * it is an exception taken branch. > + */ > + if (prev_packet->sample_type == CS_ETM_RANGE) > + prev_packet->flags = packet->flags; > + break; > case CS_ETM_EXCEPTION_RET: > case CS_ETM_EMPTY: > default: > diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h > index 5d70d10f3907..7bd16ea8a62d 100644 > --- a/tools/perf/util/cs-etm.h > +++ b/tools/perf/util/cs-etm.h > @@ -53,6 +53,50 @@ enum { > CS_ETMV4_PRIV_MAX, > }; > > +/* > + * ETMv3 exception encoding number: > + * See Embedded Trace Macrocell spcification (ARM IHI 0014Q) > + * table 7-12 Encoding of Exception[3:0] for non-ARMv7-M processors. > + */ > +enum { > + CS_ETMV3_EXC_NONE = 0, > + CS_ETMV3_EXC_DEBUG_HALT = 1, > + CS_ETMV3_EXC_SMC = 2, > + CS_ETMV3_EXC_HYP = 3, > + CS_ETMV3_EXC_ASYNC_DATA_ABORT = 4, > + CS_ETMV3_EXC_JAZELLE_THUMBEE = 5, > + CS_ETMV3_EXC_PE_RESET = 8, > + CS_ETMV3_EXC_UNDEFINED_INSTR = 9, > + CS_ETMV3_EXC_SVC = 10, > + CS_ETMV3_EXC_PREFETCH_ABORT = 11, > + CS_ETMV3_EXC_DATA_FAULT = 12, > + CS_ETMV3_EXC_GENERIC = 13, > + CS_ETMV3_EXC_IRQ = 14, > + CS_ETMV3_EXC_FIQ = 15, > +}; > + > +/* > + * ETMv4 exception encoding number: > + * See ARM Embedded Trace Macrocell Architecture Specification (ARM IHI 0064D) > + * table 6-12 Possible values for the TYPE field in an Exception instruction > + * trace packet, for ARMv7-A/R and ARMv8-A/R PEs. > + */ > +enum { > + CS_ETMV4_EXC_RESET = 0, > + CS_ETMV4_EXC_DEBUG_HALT = 1, > + CS_ETMV4_EXC_CALL = 2, > + CS_ETMV4_EXC_TRAP = 3, > + CS_ETMV4_EXC_SYSTEM_ERROR = 4, > + CS_ETMV4_EXC_INST_DEBUG = 6, > + CS_ETMV4_EXC_DATA_DEBUG = 7, > + CS_ETMV4_EXC_ALIGNMENT = 10, > + CS_ETMV4_EXC_INST_FAULT = 11, > + CS_ETMV4_EXC_DATA_FAULT = 12, > + CS_ETMV4_EXC_IRQ = 14, > + CS_ETMV4_EXC_FIQ = 15, > + CS_ETMV4_EXC_END = 31, > +}; > + > /* RB tree for quick conversion between traceID and metadata pointers */ > struct intlist *traceid_list; > > -- > 2.17.1 >
| |