[PATCH V11_RESEND 06/10] powerpc/lib: Add new branch analysis support functions
From: Anshuman Khandual <hidden>
Date: 2016-02-16 06:38:14
Subsystem:
linux for powerpc (32-bit and 64-bit), the rest · Maintainers:
Madhavan Srinivasan, Linus Torvalds
Generic powerpc branch analysis support added in the code patching library which will help the subsequent patch on SW based filtering of branch records in perf. Signed-off-by: Anshuman Khandual <redacted> --- arch/powerpc/include/asm/code-patching.h | 15 ++++++++ arch/powerpc/lib/code-patching.c | 60 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+)
diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h
index 840a550..0a6f0d8 100644
--- a/arch/powerpc/include/asm/code-patching.h
+++ b/arch/powerpc/include/asm/code-patching.h@@ -22,6 +22,16 @@ #define BRANCH_SET_LINK 0x1 #define BRANCH_ABSOLUTE 0x2 +#define XL_FORM_LR 0x4C000020 +#define XL_FORM_CTR 0x4C000420 +#define XL_FORM_TAR 0x4C000460 + +#define BO_ALWAYS 0x02800000 +#define BO_CTR 0x02000000 +#define BO_CRBI_OFF 0x00800000 +#define BO_CRBI_ON 0x01800000 +#define BO_CRBI_HINT 0x00400000 + unsigned int create_branch(const unsigned int *addr, unsigned long target, int flags); unsigned int create_cond_branch(const unsigned int *addr,
@@ -99,4 +109,9 @@ static inline unsigned long ppc_global_function_entry(void *func) #endif } +bool instr_is_return_branch(unsigned int instr); +bool instr_is_conditional_branch(unsigned int instr); +bool instr_is_func_call(unsigned int instr); +bool instr_is_indirect_func_call(unsigned int instr); + #endif /* _ASM_POWERPC_CODE_PATCHING_H */
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index d5edbeb..46fbcca 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c@@ -87,6 +87,66 @@ static int instr_is_branch_bform(unsigned int instr) return branch_opcode(instr) == 16; } +static bool instr_is_branch_xlform(unsigned int instr) +{ + return branch_opcode(instr) == 19; +} + +static bool is_xlform_lr(unsigned int instr) +{ + return (instr & XL_FORM_LR) == XL_FORM_LR; +} + +static bool is_bo_always(unsigned int instr) +{ + return (instr & BO_ALWAYS) == BO_ALWAYS; +} + +static bool is_branch_link_set(unsigned int instr) +{ + return (instr & BRANCH_SET_LINK) == BRANCH_SET_LINK; +} + +bool instr_is_return_branch(unsigned int instr) +{ + /* + * Conditional and unconditional branch to LR register + * without seting the link register. + */ + if (is_xlform_lr(instr) && !is_branch_link_set(instr)) + return true; + + return false; +} + +bool instr_is_conditional_branch(unsigned int instr) +{ + /* I-form instruction - excluded */ + if (instr_is_branch_iform(instr)) + return false; + + /* B-form or XL-form instruction */ + if (instr_is_branch_bform(instr) || instr_is_branch_xlform(instr)) { + + /* Not branch always */ + if (!is_bo_always(instr)) + return true; + } + return false; +} + +bool instr_is_func_call(unsigned int instr) +{ + /* LR should be set */ + return is_branch_link_set(instr); +} + +bool instr_is_indirect_func_call(unsigned int instr) +{ + /* XL-form instruction with LR set */ + return (instr_is_branch_xlform(instr) && is_branch_link_set(instr)); +} + int instr_is_relative_branch(unsigned int instr) { if (instr & BRANCH_ABSOLUTE)
--
2.1.0