@@ -78,47 +78,76 @@ static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
7878}
7979
8080/*
81- * Turn on the call to ftrace_caller() in instrumented function
81+ * Find the address the callsite must branch to in order to reach '*addr'.
82+ *
83+ * Due to the limited range of 'BL' instructions, modules may be placed too far
84+ * away to branch directly and must use a PLT.
85+ *
86+ * Returns true when '*addr' contains a reachable target address, or has been
87+ * modified to contain a PLT address. Returns false otherwise.
8288 */
83- int ftrace_make_call (struct dyn_ftrace * rec , unsigned long addr )
89+ static bool ftrace_find_callable_addr (struct dyn_ftrace * rec ,
90+ struct module * mod ,
91+ unsigned long * addr )
8492{
8593 unsigned long pc = rec -> ip ;
86- u32 old , new ;
87- long offset = ( long ) pc - ( long ) addr ;
94+ long offset = ( long ) * addr - ( long ) pc ;
95+ struct plt_entry * plt ;
8896
89- if (offset < - SZ_128M || offset >= SZ_128M ) {
90- struct module * mod ;
91- struct plt_entry * plt ;
97+ /*
98+ * When the target is within range of the 'BL' instruction, use 'addr'
99+ * as-is and branch to that directly.
100+ */
101+ if (offset >= - SZ_128M && offset < SZ_128M )
102+ return true;
92103
93- if (!IS_ENABLED (CONFIG_ARM64_MODULE_PLTS ))
94- return - EINVAL ;
104+ /*
105+ * When the target is outside of the range of a 'BL' instruction, we
106+ * must use a PLT to reach it. We can only place PLTs for modules, and
107+ * only when module PLT support is built-in.
108+ */
109+ if (!IS_ENABLED (CONFIG_ARM64_MODULE_PLTS ))
110+ return false;
95111
96- /*
97- * On kernels that support module PLTs, the offset between the
98- * branch instruction and its target may legally exceed the
99- * range of an ordinary relative 'bl' opcode. In this case, we
100- * need to branch via a trampoline in the module.
101- *
102- * NOTE: __module_text_address() must be called with preemption
103- * disabled, but we can rely on ftrace_lock to ensure that 'mod'
104- * retains its validity throughout the remainder of this code.
105- */
112+ /*
113+ * 'mod' is only set at module load time, but if we end up
114+ * dealing with an out-of-range condition, we can assume it
115+ * is due to a module being loaded far away from the kernel.
116+ *
117+ * NOTE: __module_text_address() must be called with preemption
118+ * disabled, but we can rely on ftrace_lock to ensure that 'mod'
119+ * retains its validity throughout the remainder of this code.
120+ */
121+ if (! mod ) {
106122 preempt_disable ();
107123 mod = __module_text_address (pc );
108124 preempt_enable ();
125+ }
109126
110- if (WARN_ON (!mod ))
111- return - EINVAL ;
127+ if (WARN_ON (!mod ))
128+ return false ;
112129
113- plt = get_ftrace_plt (mod , addr );
114- if (!plt ) {
115- pr_err ("ftrace: no module PLT for %ps\n" , (void * )addr );
116- return - EINVAL ;
117- }
118-
119- addr = (unsigned long )plt ;
130+ plt = get_ftrace_plt (mod , * addr );
131+ if (!plt ) {
132+ pr_err ("ftrace: no module PLT for %ps\n" , (void * )* addr );
133+ return false;
120134 }
121135
136+ * addr = (unsigned long )plt ;
137+ return true;
138+ }
139+
140+ /*
141+ * Turn on the call to ftrace_caller() in instrumented function
142+ */
143+ int ftrace_make_call (struct dyn_ftrace * rec , unsigned long addr )
144+ {
145+ unsigned long pc = rec -> ip ;
146+ u32 old , new ;
147+
148+ if (!ftrace_find_callable_addr (rec , NULL , & addr ))
149+ return - EINVAL ;
150+
122151 old = aarch64_insn_gen_nop ();
123152 new = aarch64_insn_gen_branch_imm (pc , addr , AARCH64_INSN_BRANCH_LINK );
124153
@@ -132,6 +161,11 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
132161 unsigned long pc = rec -> ip ;
133162 u32 old , new ;
134163
164+ if (!ftrace_find_callable_addr (rec , NULL , & old_addr ))
165+ return - EINVAL ;
166+ if (!ftrace_find_callable_addr (rec , NULL , & addr ))
167+ return - EINVAL ;
168+
135169 old = aarch64_insn_gen_branch_imm (pc , old_addr ,
136170 AARCH64_INSN_BRANCH_LINK );
137171 new = aarch64_insn_gen_branch_imm (pc , addr , AARCH64_INSN_BRANCH_LINK );
@@ -181,54 +215,15 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
181215 unsigned long addr )
182216{
183217 unsigned long pc = rec -> ip ;
184- bool validate = true;
185218 u32 old = 0 , new ;
186- long offset = (long )pc - (long )addr ;
187219
188- if (offset < - SZ_128M || offset >= SZ_128M ) {
189- u32 replaced ;
190-
191- if (!IS_ENABLED (CONFIG_ARM64_MODULE_PLTS ))
192- return - EINVAL ;
193-
194- /*
195- * 'mod' is only set at module load time, but if we end up
196- * dealing with an out-of-range condition, we can assume it
197- * is due to a module being loaded far away from the kernel.
198- */
199- if (!mod ) {
200- preempt_disable ();
201- mod = __module_text_address (pc );
202- preempt_enable ();
203-
204- if (WARN_ON (!mod ))
205- return - EINVAL ;
206- }
207-
208- /*
209- * The instruction we are about to patch may be a branch and
210- * link instruction that was redirected via a PLT entry. In
211- * this case, the normal validation will fail, but we can at
212- * least check that we are dealing with a branch and link
213- * instruction that points into the right module.
214- */
215- if (aarch64_insn_read ((void * )pc , & replaced ))
216- return - EFAULT ;
217-
218- if (!aarch64_insn_is_bl (replaced ) ||
219- !within_module (pc + aarch64_get_branch_offset (replaced ),
220- mod ))
221- return - EINVAL ;
222-
223- validate = false;
224- } else {
225- old = aarch64_insn_gen_branch_imm (pc , addr ,
226- AARCH64_INSN_BRANCH_LINK );
227- }
220+ if (!ftrace_find_callable_addr (rec , mod , & addr ))
221+ return - EINVAL ;
228222
223+ old = aarch64_insn_gen_branch_imm (pc , addr , AARCH64_INSN_BRANCH_LINK );
229224 new = aarch64_insn_gen_nop ();
230225
231- return ftrace_modify_code (pc , old , new , validate );
226+ return ftrace_modify_code (pc , old , new , true );
232227}
233228
234229void arch_ftrace_update_code (int command )
0 commit comments