Skip to content

Commit dbcdbdf

Browse files
author
Peter Zijlstra
committed
objtool: Rework instruction -> symbol mapping
Currently insn->func contains a instruction -> symbol link for STT_FUNC symbols. A NULL value is assumed to mean STT_NOTYPE. However, there are also instructions not covered by any symbol at all. This can happen due to __weak symbols for example. Since the current scheme cannot differentiate between no symbol and STT_NOTYPE symbol, change things around. Make insn->sym point to any symbol type such that !insn->sym means no symbol and add a helper insn_func() that check the sym->type to retain the old functionality. This then prepares the way to add code that depends on the distinction between STT_NOTYPE and no symbol at all. Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
1 parent 08ef8c4 commit dbcdbdf

File tree

2 files changed

+66
-51
lines changed

2 files changed

+66
-51
lines changed

tools/objtool/check.c

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
6262
struct instruction *insn)
6363
{
6464
struct instruction *next = list_next_entry(insn, list);
65-
struct symbol *func = insn->func;
65+
struct symbol *func = insn_func(insn);
6666

6767
if (!func)
6868
return NULL;
6969

70-
if (&next->list != &file->insn_list && next->func == func)
70+
if (&next->list != &file->insn_list && insn_func(next) == func)
7171
return next;
7272

7373
/* Check if we're already in the subfunction: */
@@ -83,7 +83,7 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
8383
{
8484
struct instruction *prev = list_prev_entry(insn, list);
8585

86-
if (&prev->list != &file->insn_list && prev->func == insn->func)
86+
if (&prev->list != &file->insn_list && insn_func(prev) == insn_func(insn))
8787
return prev;
8888

8989
return NULL;
@@ -133,7 +133,7 @@ static bool is_sibling_call(struct instruction *insn)
133133
* sibling call detection consistency between vmlinux.o and individual
134134
* objects.
135135
*/
136-
if (!insn->func)
136+
if (!insn_func(insn))
137137
return false;
138138

139139
/* An indirect jump is either a sibling call or a jump to a table. */
@@ -207,7 +207,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
207207
return false;
208208

209209
insn = find_insn(file, func->sec, func->offset);
210-
if (!insn->func)
210+
if (!insn_func(insn))
211211
return false;
212212

213213
func_for_each_insn(file, func, insn) {
@@ -243,7 +243,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
243243
return false;
244244
}
245245

246-
return __dead_end_function(file, dest->func, recursion+1);
246+
return __dead_end_function(file, insn_func(dest), recursion+1);
247247
}
248248
}
249249

@@ -427,7 +427,10 @@ static int decode_instructions(struct objtool_file *file)
427427
}
428428

429429
list_for_each_entry(func, &sec->symbol_list, list) {
430-
if (func->type != STT_FUNC || func->alias != func)
430+
if (func->type != STT_NOTYPE && func->type != STT_FUNC)
431+
continue;
432+
433+
if (func->return_thunk || func->alias != func)
431434
continue;
432435

433436
if (!find_insn(file, sec, func->offset)) {
@@ -437,9 +440,11 @@ static int decode_instructions(struct objtool_file *file)
437440
}
438441

439442
sym_for_each_insn(file, func, insn) {
440-
insn->func = func;
441-
if (insn->type == INSN_ENDBR && list_empty(&insn->call_node)) {
442-
if (insn->offset == insn->func->offset) {
443+
insn->sym = func;
444+
if (func->type == STT_FUNC &&
445+
insn->type == INSN_ENDBR &&
446+
list_empty(&insn->call_node)) {
447+
if (insn->offset == func->offset) {
443448
list_add_tail(&insn->call_node, &file->endbr_list);
444449
file->nr_endbr++;
445450
} else {
@@ -1397,19 +1402,19 @@ static void add_return_call(struct objtool_file *file, struct instruction *insn,
13971402

13981403
static bool same_function(struct instruction *insn1, struct instruction *insn2)
13991404
{
1400-
return insn1->func->pfunc == insn2->func->pfunc;
1405+
return insn_func(insn1)->pfunc == insn_func(insn2)->pfunc;
14011406
}
14021407

14031408
static bool is_first_func_insn(struct objtool_file *file, struct instruction *insn)
14041409
{
1405-
if (insn->offset == insn->func->offset)
1410+
if (insn->offset == insn_func(insn)->offset)
14061411
return true;
14071412

14081413
if (opts.ibt) {
14091414
struct instruction *prev = prev_insn_same_sym(file, insn);
14101415

14111416
if (prev && prev->type == INSN_ENDBR &&
1412-
insn->offset == insn->func->offset + prev->len)
1417+
insn->offset == insn_func(insn)->offset + prev->len)
14131418
return true;
14141419
}
14151420

@@ -1450,7 +1455,7 @@ static int add_jump_destinations(struct objtool_file *file)
14501455
} else if (reloc->sym->return_thunk) {
14511456
add_return_call(file, insn, true);
14521457
continue;
1453-
} else if (insn->func) {
1458+
} else if (insn_func(insn)) {
14541459
/*
14551460
* External sibling call or internal sibling call with
14561461
* STT_FUNC reloc.
@@ -1492,8 +1497,8 @@ static int add_jump_destinations(struct objtool_file *file)
14921497
/*
14931498
* Cross-function jump.
14941499
*/
1495-
if (insn->func && jump_dest->func &&
1496-
insn->func != jump_dest->func) {
1500+
if (insn_func(insn) && insn_func(jump_dest) &&
1501+
insn_func(insn) != insn_func(jump_dest)) {
14971502

14981503
/*
14991504
* For GCC 8+, create parent/child links for any cold
@@ -1510,18 +1515,18 @@ static int add_jump_destinations(struct objtool_file *file)
15101515
* case where the parent function's only reference to a
15111516
* subfunction is through a jump table.
15121517
*/
1513-
if (!strstr(insn->func->name, ".cold") &&
1514-
strstr(jump_dest->func->name, ".cold")) {
1515-
insn->func->cfunc = jump_dest->func;
1516-
jump_dest->func->pfunc = insn->func;
1518+
if (!strstr(insn_func(insn)->name, ".cold") &&
1519+
strstr(insn_func(jump_dest)->name, ".cold")) {
1520+
insn_func(insn)->cfunc = insn_func(jump_dest);
1521+
insn_func(jump_dest)->pfunc = insn_func(insn);
15171522

15181523
} else if (!same_function(insn, jump_dest) &&
15191524
is_first_func_insn(file, jump_dest)) {
15201525
/*
15211526
* Internal sibling call without reloc or with
15221527
* STT_SECTION reloc.
15231528
*/
1524-
add_call_dest(file, insn, jump_dest->func, true);
1529+
add_call_dest(file, insn, insn_func(jump_dest), true);
15251530
continue;
15261531
}
15271532
}
@@ -1572,7 +1577,7 @@ static int add_call_destinations(struct objtool_file *file)
15721577
return -1;
15731578
}
15741579

1575-
if (insn->func && insn->call_dest->type != STT_FUNC) {
1580+
if (insn_func(insn) && insn->call_dest->type != STT_FUNC) {
15761581
WARN_FUNC("unsupported call to non-function",
15771582
insn->sec, insn->offset);
15781583
return -1;
@@ -1668,7 +1673,7 @@ static int handle_group_alt(struct objtool_file *file,
16681673
nop->offset = special_alt->new_off + special_alt->new_len;
16691674
nop->len = special_alt->orig_len - special_alt->new_len;
16701675
nop->type = INSN_NOP;
1671-
nop->func = orig_insn->func;
1676+
nop->sym = orig_insn->sym;
16721677
nop->alt_group = new_alt_group;
16731678
nop->ignore = orig_insn->ignore_alts;
16741679
}
@@ -1688,7 +1693,7 @@ static int handle_group_alt(struct objtool_file *file,
16881693
last_new_insn = insn;
16891694

16901695
insn->ignore = orig_insn->ignore_alts;
1691-
insn->func = orig_insn->func;
1696+
insn->sym = orig_insn->sym;
16921697
insn->alt_group = new_alt_group;
16931698

16941699
/*
@@ -1882,7 +1887,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
18821887
struct reloc *reloc = table;
18831888
struct instruction *dest_insn;
18841889
struct alternative *alt;
1885-
struct symbol *pfunc = insn->func->pfunc;
1890+
struct symbol *pfunc = insn_func(insn)->pfunc;
18861891
unsigned int prev_offset = 0;
18871892

18881893
/*
@@ -1909,7 +1914,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
19091914
break;
19101915

19111916
/* Make sure the destination is in the same function: */
1912-
if (!dest_insn->func || dest_insn->func->pfunc != pfunc)
1917+
if (!insn_func(dest_insn) || insn_func(dest_insn)->pfunc != pfunc)
19131918
break;
19141919

19151920
alt = malloc(sizeof(*alt));
@@ -1949,7 +1954,7 @@ static struct reloc *find_jump_table(struct objtool_file *file,
19491954
* it.
19501955
*/
19511956
for (;
1952-
insn && insn->func && insn->func->pfunc == func;
1957+
insn && insn_func(insn) && insn_func(insn)->pfunc == func;
19531958
insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) {
19541959

19551960
if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
@@ -1966,7 +1971,7 @@ static struct reloc *find_jump_table(struct objtool_file *file,
19661971
if (!table_reloc)
19671972
continue;
19681973
dest_insn = find_insn(file, table_reloc->sym->sec, table_reloc->addend);
1969-
if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc != func)
1974+
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
19701975
continue;
19711976

19721977
return table_reloc;
@@ -2415,6 +2420,13 @@ static int decode_sections(struct objtool_file *file)
24152420
if (ret)
24162421
return ret;
24172422

2423+
/*
2424+
* Must be before add_{jump_call}_destination.
2425+
*/
2426+
ret = classify_symbols(file);
2427+
if (ret)
2428+
return ret;
2429+
24182430
ret = decode_instructions(file);
24192431
if (ret)
24202432
return ret;
@@ -2433,13 +2445,6 @@ static int decode_sections(struct objtool_file *file)
24332445
if (ret)
24342446
return ret;
24352447

2436-
/*
2437-
* Must be before add_{jump_call}_destination.
2438-
*/
2439-
ret = classify_symbols(file);
2440-
if (ret)
2441-
return ret;
2442-
24432448
/*
24442449
* Must be before add_jump_destinations(), which depends on 'func'
24452450
* being set for alternatives, to enable proper sibling call detection.
@@ -2648,7 +2653,7 @@ static int update_cfi_state(struct instruction *insn,
26482653

26492654
/* stack operations don't make sense with an undefined CFA */
26502655
if (cfa->base == CFI_UNDEFINED) {
2651-
if (insn->func) {
2656+
if (insn_func(insn)) {
26522657
WARN_FUNC("undefined stack state", insn->sec, insn->offset);
26532658
return -1;
26542659
}
@@ -2994,7 +2999,7 @@ static int update_cfi_state(struct instruction *insn,
29942999
}
29953000

29963001
/* detect when asm code uses rbp as a scratch register */
2997-
if (opts.stackval && insn->func && op->src.reg == CFI_BP &&
3002+
if (opts.stackval && insn_func(insn) && op->src.reg == CFI_BP &&
29983003
cfa->base != CFI_BP)
29993004
cfi->bp_scratch = true;
30003005
break;
@@ -3390,13 +3395,13 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
33903395
while (1) {
33913396
next_insn = next_insn_to_validate(file, insn);
33923397

3393-
if (func && insn->func && func != insn->func->pfunc) {
3398+
if (func && insn_func(insn) && func != insn_func(insn)->pfunc) {
33943399
/* Ignore KCFI type preambles, which always fall through */
33953400
if (!strncmp(func->name, "__cfi_", 6))
33963401
return 0;
33973402

33983403
WARN("%s() falls through to next function %s()",
3399-
func->name, insn->func->name);
3404+
func->name, insn_func(insn)->name);
34003405
return 1;
34013406
}
34023407

@@ -3638,7 +3643,7 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
36383643

36393644
while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) {
36403645
if (insn->hint && !insn->visited && !insn->ignore) {
3641-
ret = validate_branch(file, insn->func, insn, state);
3646+
ret = validate_branch(file, insn_func(insn), insn, state);
36423647
if (ret && opts.backtrace)
36433648
BT_FUNC("<=== (hint)", insn);
36443649
warnings += ret;
@@ -3861,7 +3866,7 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
38613866
* In this case we'll find a piece of code (whole function) that is not
38623867
* covered by a !section symbol. Ignore them.
38633868
*/
3864-
if (opts.link && !insn->func) {
3869+
if (opts.link && !insn_func(insn)) {
38653870
int size = find_symbol_hole_containing(insn->sec, insn->offset);
38663871
unsigned long end = insn->offset + size;
38673872

@@ -3885,21 +3890,21 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
38853890
/*
38863891
* If this hole jumps to a .cold function, mark it ignore too.
38873892
*/
3888-
if (insn->jump_dest && insn->jump_dest->func &&
3889-
strstr(insn->jump_dest->func->name, ".cold")) {
3893+
if (insn->jump_dest && insn_func(insn->jump_dest) &&
3894+
strstr(insn_func(insn->jump_dest)->name, ".cold")) {
38903895
struct instruction *dest = insn->jump_dest;
3891-
func_for_each_insn(file, dest->func, dest)
3896+
func_for_each_insn(file, insn_func(dest), dest)
38923897
dest->ignore = true;
38933898
}
38943899
}
38953900

38963901
return false;
38973902
}
38983903

3899-
if (!insn->func)
3904+
if (!insn_func(insn))
39003905
return false;
39013906

3902-
if (insn->func->static_call_tramp)
3907+
if (insn_func(insn)->static_call_tramp)
39033908
return true;
39043909

39053910
/*
@@ -3930,15 +3935,15 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
39303935

39313936
if (insn->type == INSN_JUMP_UNCONDITIONAL) {
39323937
if (insn->jump_dest &&
3933-
insn->jump_dest->func == insn->func) {
3938+
insn_func(insn->jump_dest) == insn_func(insn)) {
39343939
insn = insn->jump_dest;
39353940
continue;
39363941
}
39373942

39383943
break;
39393944
}
39403945

3941-
if (insn->offset + insn->len >= insn->func->offset + insn->func->len)
3946+
if (insn->offset + insn->len >= insn_func(insn)->offset + insn_func(insn)->len)
39423947
break;
39433948

39443949
insn = list_next_entry(insn, list);
@@ -3967,7 +3972,7 @@ static int validate_symbol(struct objtool_file *file, struct section *sec,
39673972

39683973
state->uaccess = sym->uaccess_safe;
39693974

3970-
ret = validate_branch(file, insn->func, insn, *state);
3975+
ret = validate_branch(file, insn_func(insn), insn, *state);
39713976
if (ret && opts.backtrace)
39723977
BT_FUNC("<=== (sym)", insn);
39733978
return ret;
@@ -4104,7 +4109,7 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
41044109
continue;
41054110
}
41064111

4107-
if (dest->func && dest->func == insn->func) {
4112+
if (insn_func(dest) && insn_func(dest) == insn_func(insn)) {
41084113
/*
41094114
* Anything from->to self is either _THIS_IP_ or
41104115
* IRET-to-self.

tools/objtool/include/objtool/check.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,21 @@ struct instruction {
6767
struct reloc *jump_table;
6868
struct reloc *reloc;
6969
struct list_head alts;
70-
struct symbol *func;
70+
struct symbol *sym;
7171
struct list_head stack_ops;
7272
struct cfi_state *cfi;
7373
};
7474

75+
static inline struct symbol *insn_func(struct instruction *insn)
76+
{
77+
struct symbol *sym = insn->sym;
78+
79+
if (sym && sym->type != STT_FUNC)
80+
sym = NULL;
81+
82+
return sym;
83+
}
84+
7585
#define VISITED_BRANCH 0x01
7686
#define VISITED_BRANCH_UACCESS 0x02
7787
#define VISITED_BRANCH_MASK 0x03

0 commit comments

Comments
 (0)