Skip to content

Commit 74aec05

Browse files
jpoimboeIngo Molnar
authored andcommitted
objtool: Add helper macros for traversing instructions
Add some helper macros to make it easier to traverse instructions, and to abstract the details of the instruction list implementation in preparation for creating a hash structure. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Bernd Petrovitsch <bernd@petrovitsch.priv.at> Cc: Borislav Petkov <bp@alien8.de> Cc: Chris J Arges <chris.j.arges@canonical.com> Cc: Jiri Slaby <jslaby@suse.cz> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Michal Marek <mmarek@suse.cz> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Pedro Alves <palves@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: live-patching@vger.kernel.org Link: http://lkml.kernel.org/r/8e1715d5035bc02b4db28d0fccef6bb1170d1f12.1457502970.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent d8d1b2c commit 74aec05

File tree

1 file changed

+55
-73
lines changed

1 file changed

+55
-73
lines changed

tools/objtool/builtin-check.c

Lines changed: 55 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,8 @@ struct objtool_file {
6666
const char *objname;
6767
static bool nofp;
6868

69-
static struct instruction *find_instruction(struct objtool_file *file,
70-
struct section *sec,
71-
unsigned long offset)
69+
static struct instruction *find_insn(struct objtool_file *file,
70+
struct section *sec, unsigned long offset)
7271
{
7372
struct instruction *insn;
7473

@@ -79,6 +78,31 @@ static struct instruction *find_instruction(struct objtool_file *file,
7978
return NULL;
8079
}
8180

81+
static struct instruction *next_insn_same_sec(struct objtool_file *file,
82+
struct instruction *insn)
83+
{
84+
struct instruction *next = list_next_entry(insn, list);
85+
86+
if (&next->list == &file->insns || next->sec != insn->sec)
87+
return NULL;
88+
89+
return next;
90+
}
91+
92+
#define for_each_insn(file, insn) \
93+
list_for_each_entry(insn, &file->insns, list)
94+
95+
#define func_for_each_insn(file, func, insn) \
96+
for (insn = find_insn(file, func->sec, func->offset); \
97+
insn && &insn->list != &file->insns && \
98+
insn->sec == func->sec && \
99+
insn->offset < func->offset + func->len; \
100+
insn = list_next_entry(insn, list))
101+
102+
#define sec_for_each_insn_from(file, insn) \
103+
for (; insn; insn = next_insn_same_sec(file, insn))
104+
105+
82106
/*
83107
* Check if the function has been manually whitelisted with the
84108
* STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted
@@ -99,16 +123,9 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func)
99123
return true;
100124

101125
/* check if it has a context switching instruction */
102-
insn = find_instruction(file, func->sec, func->offset);
103-
if (!insn)
104-
return false;
105-
list_for_each_entry_from(insn, &file->insns, list) {
106-
if (insn->sec != func->sec ||
107-
insn->offset >= func->offset + func->len)
108-
break;
126+
func_for_each_insn(file, func, insn)
109127
if (insn->type == INSN_CONTEXT_SWITCH)
110128
return true;
111-
}
112129

113130
return false;
114131
}
@@ -131,7 +148,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
131148
int recursion)
132149
{
133150
int i;
134-
struct instruction *insn, *func_insn;
151+
struct instruction *insn;
135152
bool empty = true;
136153

137154
/*
@@ -160,16 +177,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
160177
if (!func->sec)
161178
return 0;
162179

163-
func_insn = find_instruction(file, func->sec, func->offset);
164-
if (!func_insn)
165-
return 0;
166-
167-
insn = func_insn;
168-
list_for_each_entry_from(insn, &file->insns, list) {
169-
if (insn->sec != func->sec ||
170-
insn->offset >= func->offset + func->len)
171-
break;
172-
180+
func_for_each_insn(file, func, insn) {
173181
empty = false;
174182

175183
if (insn->type == INSN_RETURN)
@@ -184,8 +192,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
184192
* case, the function's dead-end status depends on whether the target
185193
* of the sibling call returns.
186194
*/
187-
insn = func_insn;
188-
list_for_each_entry_from(insn, &file->insns, list) {
195+
func_for_each_insn(file, func, insn) {
189196
if (insn->sec != func->sec ||
190197
insn->offset >= func->offset + func->len)
191198
break;
@@ -294,17 +301,8 @@ static void get_ignores(struct objtool_file *file)
294301
if (!ignore_func(file, func))
295302
continue;
296303

297-
insn = find_instruction(file, sec, func->offset);
298-
if (!insn)
299-
continue;
300-
301-
list_for_each_entry_from(insn, &file->insns, list) {
302-
if (insn->sec != func->sec ||
303-
insn->offset >= func->offset + func->len)
304-
break;
305-
304+
func_for_each_insn(file, func, insn)
306305
insn->visited = true;
307-
}
308306
}
309307
}
310308
}
@@ -319,7 +317,7 @@ static int get_jump_destinations(struct objtool_file *file)
319317
struct section *dest_sec;
320318
unsigned long dest_off;
321319

322-
list_for_each_entry(insn, &file->insns, list) {
320+
for_each_insn(file, insn) {
323321
if (insn->type != INSN_JUMP_CONDITIONAL &&
324322
insn->type != INSN_JUMP_UNCONDITIONAL)
325323
continue;
@@ -345,7 +343,7 @@ static int get_jump_destinations(struct objtool_file *file)
345343
continue;
346344
}
347345

348-
insn->jump_dest = find_instruction(file, dest_sec, dest_off);
346+
insn->jump_dest = find_insn(file, dest_sec, dest_off);
349347
if (!insn->jump_dest) {
350348

351349
/*
@@ -375,7 +373,7 @@ static int get_call_destinations(struct objtool_file *file)
375373
unsigned long dest_off;
376374
struct rela *rela;
377375

378-
list_for_each_entry(insn, &file->insns, list) {
376+
for_each_insn(file, insn) {
379377
if (insn->type != INSN_CALL)
380378
continue;
381379

@@ -438,9 +436,8 @@ static int handle_group_alt(struct objtool_file *file,
438436

439437
last_orig_insn = NULL;
440438
insn = orig_insn;
441-
list_for_each_entry_from(insn, &file->insns, list) {
442-
if (insn->sec != special_alt->orig_sec ||
443-
insn->offset >= special_alt->orig_off + special_alt->orig_len)
439+
sec_for_each_insn_from(file, insn) {
440+
if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
444441
break;
445442

446443
if (special_alt->skip_orig)
@@ -450,8 +447,7 @@ static int handle_group_alt(struct objtool_file *file,
450447
last_orig_insn = insn;
451448
}
452449

453-
if (list_is_last(&last_orig_insn->list, &file->insns) ||
454-
list_next_entry(last_orig_insn, list)->sec != special_alt->orig_sec) {
450+
if (!next_insn_same_sec(file, last_orig_insn)) {
455451
WARN("%s: don't know how to handle alternatives at end of section",
456452
special_alt->orig_sec->name);
457453
return -1;
@@ -476,9 +472,8 @@ static int handle_group_alt(struct objtool_file *file,
476472

477473
last_new_insn = NULL;
478474
insn = *new_insn;
479-
list_for_each_entry_from(insn, &file->insns, list) {
480-
if (insn->sec != special_alt->new_sec ||
481-
insn->offset >= special_alt->new_off + special_alt->new_len)
475+
sec_for_each_insn_from(file, insn) {
476+
if (insn->offset >= special_alt->new_off + special_alt->new_len)
482477
break;
483478

484479
last_new_insn = insn;
@@ -561,8 +556,8 @@ static int get_special_section_alts(struct objtool_file *file)
561556
goto out;
562557
}
563558

564-
orig_insn = find_instruction(file, special_alt->orig_sec,
565-
special_alt->orig_off);
559+
orig_insn = find_insn(file, special_alt->orig_sec,
560+
special_alt->orig_off);
566561
if (!orig_insn) {
567562
WARN_FUNC("special: can't find orig instruction",
568563
special_alt->orig_sec, special_alt->orig_off);
@@ -572,8 +567,8 @@ static int get_special_section_alts(struct objtool_file *file)
572567

573568
new_insn = NULL;
574569
if (!special_alt->group || special_alt->new_len) {
575-
new_insn = find_instruction(file, special_alt->new_sec,
576-
special_alt->new_off);
570+
new_insn = find_insn(file, special_alt->new_sec,
571+
special_alt->new_off);
577572
if (!new_insn) {
578573
WARN_FUNC("special: can't find new instruction",
579574
special_alt->new_sec,
@@ -619,7 +614,7 @@ static int get_switch_alts(struct objtool_file *file)
619614
struct symbol *func;
620615
struct alternative *alt;
621616

622-
list_for_each_entry(insn, &file->insns, list) {
617+
for_each_insn(file, insn) {
623618
if (insn->type != INSN_JUMP_DYNAMIC)
624619
continue;
625620

@@ -655,8 +650,7 @@ static int get_switch_alts(struct objtool_file *file)
655650
rela->addend >= func->offset + func->len)
656651
break;
657652

658-
alt_insn = find_instruction(file, insn->sec,
659-
rela->addend);
653+
alt_insn = find_insn(file, insn->sec, rela->addend);
660654
if (!alt_insn) {
661655
WARN("%s: can't find instruction at %s+0x%x",
662656
rodata->rela->name, insn->sec->name,
@@ -881,9 +875,8 @@ static int validate_branch(struct objtool_file *file,
881875
break;
882876
}
883877

884-
insn = list_next_entry(insn, list);
885-
886-
if (&insn->list == &file->insns || insn->sec != sec) {
878+
insn = next_insn_same_sec(file, insn);
879+
if (!insn) {
887880
WARN("%s: unexpected end of section", sec->name);
888881
warnings++;
889882
return warnings;
@@ -934,8 +927,8 @@ static bool is_ubsan_insn(struct instruction *insn)
934927
"__ubsan_handle_builtin_unreachable"));
935928
}
936929

937-
static bool ignore_unreachable_insn(struct instruction *insn,
938-
unsigned long func_end)
930+
static bool ignore_unreachable_insn(struct symbol *func,
931+
struct instruction *insn)
939932
{
940933
int i;
941934

@@ -961,7 +954,7 @@ static bool ignore_unreachable_insn(struct instruction *insn,
961954
continue;
962955
}
963956

964-
if (insn->offset + insn->len >= func_end)
957+
if (insn->offset + insn->len >= func->offset + func->len)
965958
break;
966959
insn = list_next_entry(insn, list);
967960
}
@@ -974,15 +967,14 @@ static int validate_functions(struct objtool_file *file)
974967
struct section *sec;
975968
struct symbol *func;
976969
struct instruction *insn;
977-
unsigned long func_end;
978970
int ret, warnings = 0;
979971

980972
list_for_each_entry(sec, &file->elf->sections, list) {
981973
list_for_each_entry(func, &sec->symbols, list) {
982974
if (func->type != STT_FUNC)
983975
continue;
984976

985-
insn = find_instruction(file, sec, func->offset);
977+
insn = find_insn(file, sec, func->offset);
986978
if (!insn) {
987979
WARN("%s(): can't find starting instruction",
988980
func->name);
@@ -1000,21 +992,11 @@ static int validate_functions(struct objtool_file *file)
1000992
if (func->type != STT_FUNC)
1001993
continue;
1002994

1003-
insn = find_instruction(file, sec, func->offset);
1004-
if (!insn)
1005-
continue;
1006-
1007-
func_end = func->offset + func->len;
1008-
1009-
list_for_each_entry_from(insn, &file->insns, list) {
1010-
if (insn->sec != func->sec ||
1011-
insn->offset >= func_end)
1012-
break;
1013-
995+
func_for_each_insn(file, func, insn) {
1014996
if (insn->visited)
1015997
continue;
1016998

1017-
if (!ignore_unreachable_insn(insn, func_end)) {
999+
if (!ignore_unreachable_insn(func, insn)) {
10181000
WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset);
10191001
warnings++;
10201002
}
@@ -1032,7 +1014,7 @@ static int validate_uncallable_instructions(struct objtool_file *file)
10321014
struct instruction *insn;
10331015
int warnings = 0;
10341016

1035-
list_for_each_entry(insn, &file->insns, list) {
1017+
for_each_insn(file, insn) {
10361018
if (!insn->visited && insn->type == INSN_RETURN) {
10371019
WARN_FUNC("return instruction outside of a callable function",
10381020
insn->sec, insn->offset);

0 commit comments

Comments
 (0)