Skip to content

Commit 6738573

Browse files
rnavmpe
authored andcommitted
powerpc/ftrace: Simplify ftrace_modify_call()
Now that we validate the ftrace location during initialization in ftrace_init_nop(), we can simplify ftrace_modify_call() to patch-in the updated branch instruction without worrying about the instructions surrounding the ftrace location. Note that we continue to ensure we have the expected branch instruction at the ftrace location before patching it with the updated branch destination. Signed-off-by: Naveen N Rao <naveen@kernel.org> Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/06275720939f8ee4c2f61c9e9a3e89b1fa3c441d.1687166935.git.naveen@kernel.org
1 parent 9365e23 commit 6738573

1 file changed

Lines changed: 21 additions & 140 deletions

File tree

arch/powerpc/kernel/trace/ftrace.c

Lines changed: 21 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -89,33 +89,11 @@ static inline int ftrace_modify_code(unsigned long ip, ppc_inst_t old, ppc_inst_
8989
return ret;
9090
}
9191

92-
/*
93-
* Helper functions that are the same for both PPC64 and PPC32.
94-
*/
95-
static int test_24bit_addr(unsigned long ip, unsigned long addr)
96-
{
97-
addr = ppc_function_entry((void *)addr);
98-
99-
return is_offset_in_branch_range(addr - ip);
100-
}
101-
10292
static int is_bl_op(ppc_inst_t op)
10393
{
10494
return (ppc_inst_val(op) & ~PPC_LI_MASK) == PPC_RAW_BL(0);
10595
}
10696

107-
static unsigned long find_bl_target(unsigned long ip, ppc_inst_t op)
108-
{
109-
int offset;
110-
111-
offset = PPC_LI(ppc_inst_val(op));
112-
/* make it signed */
113-
if (offset & 0x02000000)
114-
offset |= 0xfe000000;
115-
116-
return ip + (long)offset;
117-
}
118-
11997
static unsigned long find_ftrace_tramp(unsigned long ip)
12098
{
12199
int i;
@@ -130,136 +108,39 @@ static unsigned long find_ftrace_tramp(unsigned long ip)
130108
}
131109

132110
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
133-
#ifdef CONFIG_MODULES
134-
static int
135-
__ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
136-
unsigned long addr)
111+
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr)
137112
{
138-
ppc_inst_t op;
139-
unsigned long ip = rec->ip;
140-
unsigned long entry, ptr, tramp;
141-
struct module *mod = rec->arch.mod;
142-
143-
/* If we never set up ftrace trampolines, then bail */
144-
if (!mod->arch.tramp || !mod->arch.tramp_regs) {
145-
pr_err("No ftrace trampoline\n");
146-
return -EINVAL;
147-
}
148-
149-
/* read where this goes */
150-
if (copy_inst_from_kernel_nofault(&op, (void *)ip)) {
151-
pr_err("Fetching opcode failed.\n");
152-
return -EFAULT;
153-
}
154-
155-
/* Make sure that this is still a 24bit jump */
156-
if (!is_bl_op(op)) {
157-
pr_err("Not expected bl: opcode is %08lx\n", ppc_inst_as_ulong(op));
158-
return -EINVAL;
159-
}
160-
161-
/* lets find where the pointer goes */
162-
tramp = find_bl_target(ip, op);
163-
entry = ppc_global_function_entry((void *)old_addr);
164-
165-
pr_devel("ip:%lx jumps to %lx", ip, tramp);
166-
167-
if (tramp != entry) {
168-
/* old_addr is not within range, so we must have used a trampoline */
169-
if (module_trampoline_target(mod, tramp, &ptr)) {
170-
pr_err("Failed to get trampoline target\n");
171-
return -EFAULT;
172-
}
173-
174-
pr_devel("trampoline target %lx", ptr);
175-
176-
/* This should match what was called */
177-
if (ptr != entry) {
178-
pr_err("addr %lx does not match expected %lx\n", ptr, entry);
179-
return -EINVAL;
180-
}
181-
}
182-
183-
/* The new target may be within range */
184-
if (test_24bit_addr(ip, addr)) {
185-
/* within range */
186-
if (patch_branch((u32 *)ip, addr, BRANCH_SET_LINK)) {
187-
pr_err("REL24 out of range!\n");
188-
return -EINVAL;
189-
}
190-
191-
return 0;
192-
}
193-
194-
if (rec->flags & FTRACE_FL_REGS)
195-
tramp = mod->arch.tramp_regs;
196-
else
197-
tramp = mod->arch.tramp;
198-
199-
if (module_trampoline_target(mod, tramp, &ptr)) {
200-
pr_err("Failed to get trampoline target\n");
201-
return -EFAULT;
202-
}
203-
204-
pr_devel("trampoline target %lx", ptr);
205-
206-
entry = ppc_global_function_entry((void *)addr);
207-
/* This should match what was called */
208-
if (ptr != entry) {
209-
pr_err("addr %lx does not match expected %lx\n", ptr, entry);
210-
return -EINVAL;
211-
}
212-
213-
if (patch_branch((u32 *)ip, tramp, BRANCH_SET_LINK)) {
214-
pr_err("REL24 out of range!\n");
215-
return -EINVAL;
216-
}
217-
218-
return 0;
219-
}
220-
#else
221-
static int __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr)
222-
{
223-
return 0;
224-
}
225-
#endif
226-
227-
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
228-
unsigned long addr)
229-
{
230-
unsigned long ip = rec->ip;
113+
unsigned long tramp, tramp_old, ip = rec->ip;
231114
ppc_inst_t old, new;
115+
struct module *mod;
232116

233-
/*
234-
* If the calling address is more that 24 bits away,
235-
* then we had to use a trampoline to make the call.
236-
* Otherwise just update the call site.
237-
*/
238-
if (test_24bit_addr(ip, addr) && test_24bit_addr(ip, old_addr)) {
239-
/* within range */
240-
old = ftrace_call_replace(ip, old_addr, 1);
241-
new = ftrace_call_replace(ip, addr, 1);
117+
if (is_offset_in_branch_range(old_addr - ip) && is_offset_in_branch_range(addr - ip)) {
118+
/* Within range */
119+
old = ftrace_create_branch_inst(ip, old_addr, 1);
120+
new = ftrace_create_branch_inst(ip, addr, 1);
242121
return ftrace_modify_code(ip, old, new);
243122
} else if (core_kernel_text(ip)) {
244123
/*
245124
* We always patch out of range locations to go to the regs
246125
* variant, so there is nothing to do here
247126
*/
248127
return 0;
249-
} else if (!IS_ENABLED(CONFIG_MODULES)) {
250-
/* We should not get here without modules */
251-
return -EINVAL;
252-
}
253-
254-
/*
255-
* Out of range jumps are called from modules.
256-
*/
257-
if (!rec->arch.mod) {
258-
pr_err("No module loaded\n");
259-
return -EINVAL;
128+
} else if (IS_ENABLED(CONFIG_MODULES)) {
129+
/* Module code would be going to one of the module stubs */
130+
mod = rec->arch.mod;
131+
if (addr == (unsigned long)ftrace_caller) {
132+
tramp_old = mod->arch.tramp_regs;
133+
tramp = mod->arch.tramp;
134+
} else {
135+
tramp_old = mod->arch.tramp;
136+
tramp = mod->arch.tramp_regs;
137+
}
138+
old = ftrace_create_branch_inst(ip, tramp_old, 1);
139+
new = ftrace_create_branch_inst(ip, tramp, 1);
140+
return ftrace_modify_code(ip, old, new);
260141
}
261142

262-
return __ftrace_modify_call(rec, old_addr, addr);
143+
return -EINVAL;
263144
}
264145
#endif
265146

0 commit comments

Comments
 (0)