From patchwork Tue Aug 23 20:36:17 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kim Phillips X-Patchwork-Id: 662039 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3sJj1J2jTLz9sCy for ; Wed, 24 Aug 2016 06:37:40 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3sJj1J1yYdzDrdC for ; Wed, 24 Aug 2016 06:37:40 +1000 (AEST) X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Received: from foss.arm.com (foss.arm.com [217.140.101.70]) by lists.ozlabs.org (Postfix) with ESMTP id 3sJhzq3TCWzDrcD for ; Wed, 24 Aug 2016 06:36:22 +1000 (AEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1E8D92F; Tue, 23 Aug 2016 13:37:58 -0700 (PDT) Received: from dupont (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5ADDE3F218; Tue, 23 Aug 2016 13:36:18 -0700 (PDT) Date: Tue, 23 Aug 2016 15:36:17 -0500 From: Kim Phillips To: Namhyung Kim Subject: Re: [PATCH v6 2/7] perf annotate: Add cross arch annotate support Message-Id: <20160823153617.c0bb45eeefe993c554cb792a@arm.com> In-Reply-To: References: <1471611578-11255-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com> <1471611578-11255-3-git-send-email-ravi.bangoria@linux.vnet.ibm.com> <20160822180151.241ad87ad1befd72bd46c2ec@arm.com> Organization: ARM X-Mailer: Sylpheed 3.5.0 (GTK+ 2.24.30; x86_64-pc-linux-gnu) Mime-Version: 1.0 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Pawel Moll , chris.ryder@arm.com, Peter Zijlstra , Hemant Kumar , Ravi Bangoria , Arnaldo Carvalho de Melo , "linux-kernel@vger.kernel.org" , Alexander Shishkin , Ingo Molnar , Taeung Song , Jiri Olsa , rmk+kernel@arm.linux.org.uk, "Naveen N. Rao" , linuxppc-dev@lists.ozlabs.org, markus@trippelsdorf.de, Masami Hiramatsu Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" On Tue, 23 Aug 2016 11:17:16 +0900 Namhyung Kim wrote: > On Tue, Aug 23, 2016 at 8:01 AM, Kim Phillips wrote: > > On Fri, 19 Aug 2016 18:29:33 +0530 > > Ravi Bangoria wrote: > > > >> Changes in v6: > >> - Instead of adding only those instructions defined in #ifdef __arm__, > >> add all instructions from default table to arm table. > > Thanks, I've gone through the list and removed all not-ARM > > instructions, and added some missing ARM branch instructions: > > Can we use regex patterns instead? Yes, that helps prevent mistakes updating instruction lists - how does this look?: Note that, for ARM, in order to match return instructions, 'lr' must be found to be the operand of the branch instruction, which is not contained in the 'name' variable passed to ins__find(). Kim diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b2c6cf3..52316f3 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -26,6 +26,7 @@ const char *disassembler_style; const char *objdump_path; static regex_t file_lineno; +static regex_t arm_call_insn, arm_jump_insn; static struct ins *ins__find(const char *name, const char *norm_arch); static int disasm_line__parse(char *line, char **namep, char **rawp); @@ -449,98 +450,7 @@ static struct ins instructions_x86[] = { { .name = "retq", .ops = &ret_ops, }, }; -static struct ins instructions_arm[] = { - { .name = "add", .ops = &mov_ops, }, - { .name = "addl", .ops = &mov_ops, }, - { .name = "addq", .ops = &mov_ops, }, - { .name = "addw", .ops = &mov_ops, }, - { .name = "and", .ops = &mov_ops, }, - { .name = "b", .ops = &jump_ops, }, /* might also be a call */ - { .name = "bcc", .ops = &jump_ops, }, - { .name = "bcs", .ops = &jump_ops, }, - { .name = "beq", .ops = &jump_ops, }, - { .name = "bge", .ops = &jump_ops, }, - { .name = "bgt", .ops = &jump_ops, }, - { .name = "bhi", .ops = &jump_ops, }, - { .name = "bl", .ops = &call_ops, }, - { .name = "bls", .ops = &jump_ops, }, - { .name = "blt", .ops = &jump_ops, }, - { .name = "blx", .ops = &call_ops, }, - { .name = "bne", .ops = &jump_ops, }, - { .name = "bts", .ops = &mov_ops, }, - { .name = "call", .ops = &call_ops, }, - { .name = "callq", .ops = &call_ops, }, - { .name = "cmp", .ops = &mov_ops, }, - { .name = "cmpb", .ops = &mov_ops, }, - { .name = "cmpl", .ops = &mov_ops, }, - { .name = "cmpq", .ops = &mov_ops, }, - { .name = "cmpw", .ops = &mov_ops, }, - { .name = "cmpxch", .ops = &mov_ops, }, - { .name = "dec", .ops = &dec_ops, }, - { .name = "decl", .ops = &dec_ops, }, - { .name = "imul", .ops = &mov_ops, }, - { .name = "inc", .ops = &dec_ops, }, - { .name = "incl", .ops = &dec_ops, }, - { .name = "ja", .ops = &jump_ops, }, - { .name = "jae", .ops = &jump_ops, }, - { .name = "jb", .ops = &jump_ops, }, - { .name = "jbe", .ops = &jump_ops, }, - { .name = "jc", .ops = &jump_ops, }, - { .name = "jcxz", .ops = &jump_ops, }, - { .name = "je", .ops = &jump_ops, }, - { .name = "jecxz", .ops = &jump_ops, }, - { .name = "jg", .ops = &jump_ops, }, - { .name = "jge", .ops = &jump_ops, }, - { .name = "jl", .ops = &jump_ops, }, - { .name = "jle", .ops = &jump_ops, }, - { .name = "jmp", .ops = &jump_ops, }, - { .name = "jmpq", .ops = &jump_ops, }, - { .name = "jna", .ops = &jump_ops, }, - { .name = "jnae", .ops = &jump_ops, }, - { .name = "jnb", .ops = &jump_ops, }, - { .name = "jnbe", .ops = &jump_ops, }, - { .name = "jnc", .ops = &jump_ops, }, - { .name = "jne", .ops = &jump_ops, }, - { .name = "jng", .ops = &jump_ops, }, - { .name = "jnge", .ops = &jump_ops, }, - { .name = "jnl", .ops = &jump_ops, }, - { .name = "jnle", .ops = &jump_ops, }, - { .name = "jno", .ops = &jump_ops, }, - { .name = "jnp", .ops = &jump_ops, }, - { .name = "jns", .ops = &jump_ops, }, - { .name = "jnz", .ops = &jump_ops, }, - { .name = "jo", .ops = &jump_ops, }, - { .name = "jp", .ops = &jump_ops, }, - { .name = "jpe", .ops = &jump_ops, }, - { .name = "jpo", .ops = &jump_ops, }, - { .name = "jrcxz", .ops = &jump_ops, }, - { .name = "js", .ops = &jump_ops, }, - { .name = "jz", .ops = &jump_ops, }, - { .name = "lea", .ops = &mov_ops, }, - { .name = "lock", .ops = &lock_ops, }, - { .name = "mov", .ops = &mov_ops, }, - { .name = "movb", .ops = &mov_ops, }, - { .name = "movdqa",.ops = &mov_ops, }, - { .name = "movl", .ops = &mov_ops, }, - { .name = "movq", .ops = &mov_ops, }, - { .name = "movslq", .ops = &mov_ops, }, - { .name = "movzbl", .ops = &mov_ops, }, - { .name = "movzwl", .ops = &mov_ops, }, - { .name = "nop", .ops = &nop_ops, }, - { .name = "nopl", .ops = &nop_ops, }, - { .name = "nopw", .ops = &nop_ops, }, - { .name = "or", .ops = &mov_ops, }, - { .name = "orl", .ops = &mov_ops, }, - { .name = "test", .ops = &mov_ops, }, - { .name = "testb", .ops = &mov_ops, }, - { .name = "testl", .ops = &mov_ops, }, - { .name = "xadd", .ops = &mov_ops, }, - { .name = "xbeginl", .ops = &jump_ops, }, - { .name = "xbeginq", .ops = &jump_ops, }, - { .name = "retq", .ops = &ret_ops, }, -}; - -struct instructions_powerpc { +struct instructions_arch { struct ins *ins; struct list_head list; }; @@ -560,41 +470,41 @@ static int ins__cmp(const void *a, const void *b) return strcmp(ia->name, ib->name); } -static struct ins *list_add__ins_powerpc(struct instructions_powerpc *head, +static struct ins *list_add__ins_arch(struct instructions_arch *head, const char *name, struct ins_ops *ops) { - struct instructions_powerpc *ins_powerpc; + struct instructions_arch *ins_arch; struct ins *ins; ins = zalloc(sizeof(struct ins)); if (!ins) return NULL; - ins_powerpc = zalloc(sizeof(struct instructions_powerpc)); - if (!ins_powerpc) + ins_arch = zalloc(sizeof(struct instructions_arch)); + if (!ins_arch) goto out_free_ins; ins->name = strdup(name); if (!ins->name) - goto out_free_ins_power; + goto out_free_ins_arch; ins->ops = ops; - ins_powerpc->ins = ins; - list_add_tail(&(ins_powerpc->list), &(head->list)); + ins_arch->ins = ins; + list_add_tail(&(ins_arch->list), &(head->list)); return ins; -out_free_ins_power: - zfree(&ins_powerpc); +out_free_ins_arch: + zfree(&ins_arch); out_free_ins: zfree(&ins); return NULL; } -static struct ins *list_search__ins_powerpc(struct instructions_powerpc *head, +static struct ins *list_search__ins_arch(struct instructions_arch *head, const char *name) { - struct instructions_powerpc *pos; + struct instructions_arch *pos; list_for_each_entry(pos, &head->list, list) { if (!strcmp(pos->ins->name, name)) @@ -608,7 +518,7 @@ static struct ins *ins__find_powerpc(const char *name) int i; struct ins *ins; struct ins_ops *ops; - static struct instructions_powerpc head; + static struct instructions_arch head; static bool list_initialized; /* @@ -629,7 +539,7 @@ static struct ins *ins__find_powerpc(const char *name) /* * Return if we already have object of 'struct ins' for this instruction */ - ins = list_search__ins_powerpc(&head, name); + ins = list_search__ins_arch(&head, name); if (ins) return ins; @@ -666,7 +576,44 @@ static struct ins *ins__find_powerpc(const char *name) * Add instruction to list so next time no need to * allocate memory for it. */ - return list_add__ins_powerpc(&head, name, ops); + return list_add__ins_arch(&head, name, ops); +} + +static struct ins *ins__find_arm(const char *name) +{ + struct ins *ins; + struct ins_ops *ops = &mov_ops; + static struct instructions_arch head; + static bool list_initialized; + regmatch_t match[2]; + int ret; + + if (!list_initialized) { + INIT_LIST_HEAD(&head.list); + list_initialized = true; + } + + /* + * Return if we already have object of 'struct ins' for this instruction + */ + ins = list_search__ins_arch(&head, name); + if (ins) + return ins; + + ret = regexec(&arm_call_insn, name, 2, match, 0); + if (!ret) { + ops = &call_ops; + } else { + ret = regexec(&arm_jump_insn, name, 2, match, 0); + if (!ret) + ops = &jump_ops; + } + + /* + * Add instruction to list so next time no need to + * allocate memory for it. + */ + return list_add__ins_arch(&head, name, ops); } static void ins__sort(struct ins *instructions, int nmemb) @@ -686,15 +633,26 @@ static const char *annotate__norm_arch(char *arch) return normalize_arch(arch); } +#define ARM_CONDS "(cc|cs|eq|ge|gt|hi|le|ls|lt|mi|ne|pl|vc|vs)" + static struct ins *ins__find(const char *name, const char *norm_arch) { static bool sorted; struct ins *instructions; - int nmemb; + int nmemb, ret; if (!sorted) { ins__sort(instructions_x86, ARRAY_SIZE(instructions_x86)); - ins__sort(instructions_arm, ARRAY_SIZE(instructions_arm)); + if (!strcmp(norm_arch, NORM_ARM)) { + ret = regcomp(&arm_call_insn, + "^blx?" ARM_CONDS "?$", REG_EXTENDED); + ret |= regcomp(&arm_jump_insn, + "^bx?" ARM_CONDS "?$", REG_EXTENDED); + if (ret) { + pr_err("regcomp failed\n"); + return NULL; + } + } sorted = true; } @@ -702,8 +660,7 @@ static struct ins *ins__find(const char *name, const char *norm_arch) instructions = instructions_x86; nmemb = ARRAY_SIZE(instructions_x86); } else if (!strcmp(norm_arch, NORM_ARM)) { - instructions = instructions_arm; - nmemb = ARRAY_SIZE(instructions_arm); + return ins__find_arm(name); } else if (!strcmp(norm_arch, NORM_POWERPC)) { return ins__find_powerpc(name); } else {