@@ -47,27 +47,29 @@ struct instruction *find_insn(struct objtool_file *file,
47
47
return NULL ;
48
48
}
49
49
50
- static struct instruction * next_insn_same_sec (struct objtool_file * file ,
51
- struct instruction * insn )
50
+ struct instruction * next_insn_same_sec (struct objtool_file * file ,
51
+ struct instruction * insn )
52
52
{
53
- struct instruction * next = list_next_entry (insn , list );
53
+ if (insn -> idx == INSN_CHUNK_MAX )
54
+ return find_insn (file , insn -> sec , insn -> offset + insn -> len );
54
55
55
- if (!next || & next -> list == & file -> insn_list || next -> sec != insn -> sec )
56
+ insn ++ ;
57
+ if (!insn -> len )
56
58
return NULL ;
57
59
58
- return next ;
60
+ return insn ;
59
61
}
60
62
61
63
static struct instruction * next_insn_same_func (struct objtool_file * file ,
62
64
struct instruction * insn )
63
65
{
64
- struct instruction * next = list_next_entry ( insn , list );
66
+ struct instruction * next = next_insn_same_sec ( file , insn );
65
67
struct symbol * func = insn_func (insn );
66
68
67
69
if (!func )
68
70
return NULL ;
69
71
70
- if (& next -> list != & file -> insn_list && insn_func (next ) == func )
72
+ if (next && insn_func (next ) == func )
71
73
return next ;
72
74
73
75
/* Check if we're already in the subfunction: */
@@ -78,34 +80,49 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
78
80
return find_insn (file , func -> cfunc -> sec , func -> cfunc -> offset );
79
81
}
80
82
83
+ static struct instruction * prev_insn_same_sec (struct objtool_file * file ,
84
+ struct instruction * insn )
85
+ {
86
+ if (insn -> idx == 0 ) {
87
+ if (insn -> prev_len )
88
+ return find_insn (file , insn -> sec , insn -> offset - insn -> prev_len );
89
+ return NULL ;
90
+ }
91
+
92
+ return insn - 1 ;
93
+ }
94
+
81
95
static struct instruction * prev_insn_same_sym (struct objtool_file * file ,
82
- struct instruction * insn )
96
+ struct instruction * insn )
83
97
{
84
- struct instruction * prev = list_prev_entry ( insn , list );
98
+ struct instruction * prev = prev_insn_same_sec ( file , insn );
85
99
86
- if (& prev -> list != & file -> insn_list && insn_func (prev ) == insn_func (insn ))
100
+ if (prev && insn_func (prev ) == insn_func (insn ))
87
101
return prev ;
88
102
89
103
return NULL ;
90
104
}
91
105
106
+ #define for_each_insn (file , insn ) \
107
+ for (struct section *__sec, *__fake = (struct section *)1; \
108
+ __fake; __fake = NULL) \
109
+ for_each_sec(file, __sec) \
110
+ sec_for_each_insn(file, __sec, insn)
111
+
92
112
#define func_for_each_insn (file , func , insn ) \
93
113
for (insn = find_insn(file, func->sec, func->offset); \
94
114
insn; \
95
115
insn = next_insn_same_func(file, insn))
96
116
97
117
#define sym_for_each_insn (file , sym , insn ) \
98
118
for (insn = find_insn(file, sym->sec, sym->offset); \
99
- insn && &insn->list != &file->insn_list && \
100
- insn->sec == sym->sec && \
101
- insn->offset < sym->offset + sym->len; \
102
- insn = list_next_entry(insn, list))
119
+ insn && insn->offset < sym->offset + sym->len; \
120
+ insn = next_insn_same_sec(file, insn))
103
121
104
122
#define sym_for_each_insn_continue_reverse (file , sym , insn ) \
105
- for (insn = list_prev_entry(insn, list); \
106
- &insn->list != &file->insn_list && \
107
- insn->sec == sym->sec && insn->offset >= sym->offset; \
108
- insn = list_prev_entry(insn, list))
123
+ for (insn = prev_insn_same_sec(file, insn); \
124
+ insn && insn->offset >= sym->offset; \
125
+ insn = prev_insn_same_sec(file, insn))
109
126
110
127
#define sec_for_each_insn_from (file , insn ) \
111
128
for (; insn; insn = next_insn_same_sec(file, insn))
@@ -384,6 +401,9 @@ static int decode_instructions(struct objtool_file *file)
384
401
int ret ;
385
402
386
403
for_each_sec (file , sec ) {
404
+ struct instruction * insns = NULL ;
405
+ u8 prev_len = 0 ;
406
+ u8 idx = 0 ;
387
407
388
408
if (!(sec -> sh .sh_flags & SHF_EXECINSTR ))
389
409
continue ;
@@ -409,22 +429,31 @@ static int decode_instructions(struct objtool_file *file)
409
429
sec -> init = true;
410
430
411
431
for (offset = 0 ; offset < sec -> sh .sh_size ; offset += insn -> len ) {
412
- insn = malloc (sizeof (* insn ));
413
- if (!insn ) {
414
- WARN ("malloc failed" );
415
- return -1 ;
432
+ if (!insns || idx == INSN_CHUNK_MAX ) {
433
+ insns = calloc (sizeof (* insn ), INSN_CHUNK_SIZE );
434
+ if (!insns ) {
435
+ WARN ("malloc failed" );
436
+ return -1 ;
437
+ }
438
+ idx = 0 ;
439
+ } else {
440
+ idx ++ ;
416
441
}
417
- memset ( insn , 0 , sizeof ( * insn )) ;
418
- INIT_LIST_HEAD ( & insn -> call_node ) ;
442
+ insn = & insns [ idx ] ;
443
+ insn -> idx = idx ;
419
444
445
+ INIT_LIST_HEAD (& insn -> call_node );
420
446
insn -> sec = sec ;
421
447
insn -> offset = offset ;
448
+ insn -> prev_len = prev_len ;
422
449
423
450
ret = arch_decode_instruction (file , sec , offset ,
424
451
sec -> sh .sh_size - offset ,
425
452
insn );
426
453
if (ret )
427
- goto err ;
454
+ return ret ;
455
+
456
+ prev_len = insn -> len ;
428
457
429
458
/*
430
459
* By default, "ud2" is a dead end unless otherwise
@@ -435,10 +464,11 @@ static int decode_instructions(struct objtool_file *file)
435
464
insn -> dead_end = true;
436
465
437
466
hash_add (file -> insn_hash , & insn -> hash , sec_offset_hash (sec , insn -> offset ));
438
- list_add_tail (& insn -> list , & file -> insn_list );
439
467
nr_insns ++ ;
440
468
}
441
469
470
+ // printf("%s: last chunk used: %d\n", sec->name, (int)idx);
471
+
442
472
list_for_each_entry (func , & sec -> symbol_list , list ) {
443
473
if (func -> type != STT_NOTYPE && func -> type != STT_FUNC )
444
474
continue ;
@@ -481,10 +511,6 @@ static int decode_instructions(struct objtool_file *file)
481
511
printf ("nr_insns: %lu\n" , nr_insns );
482
512
483
513
return 0 ;
484
-
485
- err :
486
- free (insn );
487
- return ret ;
488
514
}
489
515
490
516
/*
@@ -599,7 +625,7 @@ static int add_dead_ends(struct objtool_file *file)
599
625
}
600
626
insn = find_insn (file , reloc -> sym -> sec , reloc -> addend );
601
627
if (insn )
602
- insn = list_prev_entry ( insn , list );
628
+ insn = prev_insn_same_sec ( file , insn );
603
629
else if (reloc -> addend == reloc -> sym -> sec -> sh .sh_size ) {
604
630
insn = find_last_insn (file , reloc -> sym -> sec );
605
631
if (!insn ) {
@@ -634,7 +660,7 @@ static int add_dead_ends(struct objtool_file *file)
634
660
}
635
661
insn = find_insn (file , reloc -> sym -> sec , reloc -> addend );
636
662
if (insn )
637
- insn = list_prev_entry ( insn , list );
663
+ insn = prev_insn_same_sec ( file , insn );
638
664
else if (reloc -> addend == reloc -> sym -> sec -> sh .sh_size ) {
639
665
insn = find_last_insn (file , reloc -> sym -> sec );
640
666
if (!insn ) {
@@ -1775,6 +1801,7 @@ static int handle_group_alt(struct objtool_file *file,
1775
1801
orig_alt_group -> orig_group = NULL ;
1776
1802
orig_alt_group -> first_insn = orig_insn ;
1777
1803
orig_alt_group -> last_insn = last_orig_insn ;
1804
+ orig_alt_group -> nop = NULL ;
1778
1805
} else {
1779
1806
if (orig_alt_group -> last_insn -> offset + orig_alt_group -> last_insn -> len -
1780
1807
orig_alt_group -> first_insn -> offset != special_alt -> orig_len ) {
@@ -1876,12 +1903,11 @@ static int handle_group_alt(struct objtool_file *file,
1876
1903
return -1 ;
1877
1904
}
1878
1905
1879
- if (nop )
1880
- list_add (& nop -> list , & last_new_insn -> list );
1881
1906
end :
1882
1907
new_alt_group -> orig_group = orig_alt_group ;
1883
1908
new_alt_group -> first_insn = * new_insn ;
1884
- new_alt_group -> last_insn = nop ? : last_new_insn ;
1909
+ new_alt_group -> last_insn = last_new_insn ;
1910
+ new_alt_group -> nop = nop ;
1885
1911
new_alt_group -> cfi = orig_alt_group -> cfi ;
1886
1912
return 0 ;
1887
1913
}
@@ -1931,7 +1957,7 @@ static int handle_jump_alt(struct objtool_file *file,
1931
1957
else
1932
1958
file -> jl_long ++ ;
1933
1959
1934
- * new_insn = list_next_entry ( orig_insn , list );
1960
+ * new_insn = next_insn_same_sec ( file , orig_insn );
1935
1961
return 0 ;
1936
1962
}
1937
1963
@@ -3522,11 +3548,28 @@ static struct instruction *next_insn_to_validate(struct objtool_file *file,
3522
3548
* Simulate the fact that alternatives are patched in-place. When the
3523
3549
* end of a replacement alt_group is reached, redirect objtool flow to
3524
3550
* the end of the original alt_group.
3551
+ *
3552
+ * insn->alts->insn -> alt_group->first_insn
3553
+ * ...
3554
+ * alt_group->last_insn
3555
+ * [alt_group->nop] -> next(orig_group->last_insn)
3525
3556
*/
3526
- if (alt_group && insn == alt_group -> last_insn && alt_group -> orig_group )
3527
- return next_insn_same_sec (file , alt_group -> orig_group -> last_insn );
3557
+ if (alt_group ) {
3558
+ if (alt_group -> nop ) {
3559
+ /* ->nop implies ->orig_group */
3560
+ if (insn == alt_group -> last_insn )
3561
+ return alt_group -> nop ;
3562
+ if (insn == alt_group -> nop )
3563
+ goto next_orig ;
3564
+ }
3565
+ if (insn == alt_group -> last_insn && alt_group -> orig_group )
3566
+ goto next_orig ;
3567
+ }
3528
3568
3529
3569
return next_insn_same_sec (file , insn );
3570
+
3571
+ next_orig :
3572
+ return next_insn_same_sec (file , alt_group -> orig_group -> last_insn );
3530
3573
}
3531
3574
3532
3575
/*
@@ -3777,34 +3820,37 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
3777
3820
return 0 ;
3778
3821
}
3779
3822
3823
+ static int validate_unwind_hint (struct objtool_file * file ,
3824
+ struct instruction * insn ,
3825
+ struct insn_state * state )
3826
+ {
3827
+ if (insn -> hint && !insn -> visited && !insn -> ignore ) {
3828
+ int ret = validate_branch (file , insn_func (insn ), insn , * state );
3829
+ if (ret && opts .backtrace )
3830
+ BT_FUNC ("<=== (hint)" , insn );
3831
+ return ret ;
3832
+ }
3833
+
3834
+ return 0 ;
3835
+ }
3836
+
3780
3837
static int validate_unwind_hints (struct objtool_file * file , struct section * sec )
3781
3838
{
3782
3839
struct instruction * insn ;
3783
3840
struct insn_state state ;
3784
- int ret , warnings = 0 ;
3841
+ int warnings = 0 ;
3785
3842
3786
3843
if (!file -> hints )
3787
3844
return 0 ;
3788
3845
3789
3846
init_insn_state (file , & state , sec );
3790
3847
3791
3848
if (sec ) {
3792
- insn = find_insn (file , sec , 0 );
3793
- if (!insn )
3794
- return 0 ;
3849
+ sec_for_each_insn (file , sec , insn )
3850
+ warnings += validate_unwind_hint (file , insn , & state );
3795
3851
} else {
3796
- insn = list_first_entry (& file -> insn_list , typeof (* insn ), list );
3797
- }
3798
-
3799
- while (& insn -> list != & file -> insn_list && (!sec || insn -> sec == sec )) {
3800
- if (insn -> hint && !insn -> visited && !insn -> ignore ) {
3801
- ret = validate_branch (file , insn_func (insn ), insn , state );
3802
- if (ret && opts .backtrace )
3803
- BT_FUNC ("<=== (hint)" , insn );
3804
- warnings += ret ;
3805
- }
3806
-
3807
- insn = list_next_entry (insn , list );
3852
+ for_each_insn (file , insn )
3853
+ warnings += validate_unwind_hint (file , insn , & state );
3808
3854
}
3809
3855
3810
3856
return warnings ;
@@ -4070,7 +4116,7 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
4070
4116
*
4071
4117
* It may also insert a UD2 after calling a __noreturn function.
4072
4118
*/
4073
- prev_insn = list_prev_entry ( insn , list );
4119
+ prev_insn = prev_insn_same_sec ( file , insn );
4074
4120
if ((prev_insn -> dead_end ||
4075
4121
dead_end_function (file , insn_call_dest (prev_insn ))) &&
4076
4122
(insn -> type == INSN_BUG ||
@@ -4102,7 +4148,7 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
4102
4148
if (insn -> offset + insn -> len >= insn_func (insn )-> offset + insn_func (insn )-> len )
4103
4149
break ;
4104
4150
4105
- insn = list_next_entry ( insn , list );
4151
+ insn = next_insn_same_sec ( file , insn );
4106
4152
}
4107
4153
4108
4154
return false;
@@ -4115,10 +4161,10 @@ static int add_prefix_symbol(struct objtool_file *file, struct symbol *func,
4115
4161
return 0 ;
4116
4162
4117
4163
for (;;) {
4118
- struct instruction * prev = list_prev_entry ( insn , list );
4164
+ struct instruction * prev = prev_insn_same_sec ( file , insn );
4119
4165
u64 offset ;
4120
4166
4121
- if (& prev -> list == & file -> insn_list )
4167
+ if (! prev )
4122
4168
break ;
4123
4169
4124
4170
if (prev -> type != INSN_NOP )
@@ -4517,7 +4563,7 @@ int check(struct objtool_file *file)
4517
4563
4518
4564
warnings += ret ;
4519
4565
4520
- if (list_empty ( & file -> insn_list ) )
4566
+ if (! nr_insns )
4521
4567
goto out ;
4522
4568
4523
4569
if (opts .retpoline ) {
@@ -4626,7 +4672,7 @@ int check(struct objtool_file *file)
4626
4672
warnings += ret ;
4627
4673
}
4628
4674
4629
- if (opts .orc && ! list_empty ( & file -> insn_list ) ) {
4675
+ if (opts .orc && nr_insns ) {
4630
4676
ret = orc_create (file );
4631
4677
if (ret < 0 )
4632
4678
goto out ;
0 commit comments