lkml.org 
[lkml]   [2020]   [Jan]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself
Date
Alternatives can contain instructions that jump to another instruction
in the same alternative group. This is actually a common pattern on
arm64.

Keep track of instructions jumping within their own alternative group
and carry on validating such branches.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
tools/objtool/check.c | 48 ++++++++++++++++++++++++++++++++++---------
tools/objtool/check.h | 1 +
2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 8f2ff030936d..c7b3f1e2a628 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -722,6 +722,14 @@ static int handle_group_alt(struct objtool_file *file,
sec_for_each_insn_from(file, insn) {
if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
break;
+ /* Is insn a jump to an instruction within the alt_group */
+ if (insn->jump_dest && insn->sec == insn->jump_dest->sec &&
+ (insn->type == INSN_JUMP_CONDITIONAL ||
+ insn->type == INSN_JUMP_UNCONDITIONAL)) {
+ dest_off = insn->jump_dest->offset;
+ insn->intra_group_jump = special_alt->orig_off <= dest_off &&
+ dest_off < special_alt->orig_off + special_alt->orig_len;
+ }

insn->alt_group = true;
last_orig_insn = insn;
@@ -1853,14 +1861,33 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
return validate_call(insn, state);
}

+static int validate_branch_alt_safe(struct objtool_file *file,
+ struct symbol *func,
+ struct instruction *first,
+ struct insn_state state);
+
+static int validate_branch(struct objtool_file *file, struct symbol *func,
+ struct instruction *first, struct insn_state state)
+{
+ if (first->alt_group && list_empty(&first->alts)) {
+ WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
+ first->sec, first->offset);
+ return 1;
+ }
+
+ return validate_branch_alt_safe(file, func, first, state);
+}
+
/*
* Follow the branch starting at the given instruction, and recursively follow
* any other branches (jumps). Meanwhile, track the frame pointer state at
* each instruction and validate all the rules described in
* tools/objtool/Documentation/stack-validation.txt.
*/
-static int validate_branch(struct objtool_file *file, struct symbol *func,
- struct instruction *first, struct insn_state state)
+static int validate_branch_alt_safe(struct objtool_file *file,
+ struct symbol *func,
+ struct instruction *first,
+ struct insn_state state)
{
struct alternative *alt;
struct instruction *insn, *next_insn;
@@ -1871,12 +1898,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
insn = first;
sec = insn->sec;

- if (insn->alt_group && list_empty(&insn->alts)) {
- WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
- sec, insn->offset);
- return 1;
- }
-
while (1) {
next_insn = next_insn_same_sec(file, insn);

@@ -2023,8 +2044,15 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
return ret;

} else if (insn->jump_dest) {
- ret = validate_branch(file, func,
- insn->jump_dest, state);
+ if (insn->intra_group_jump)
+ ret = validate_branch_alt_safe(file,
+ func,
+ insn->jump_dest,
+ state);
+ else
+ ret = validate_branch(file, func,
+ insn->jump_dest,
+ state);
if (ret) {
if (backtrace)
BT_FUNC("(branch)", insn);
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index af87b55db454..d13ee02f28a4 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -46,6 +46,7 @@ struct instruction {
struct stack_op stack_op;
struct insn_state state;
struct orc_entry orc;
+ bool intra_group_jump;
};

struct objtool_file {
--
2.21.0
\
 
 \ /
  Last update: 2020-01-09 17:04    [W:0.495 / U:0.016 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site