Skip to content

Commit 403b48a

Browse files
Ada Couprie Diazwilldeacon
authored andcommitted
arm64: debug: call step handlers statically
Software stepping checks for the correct handler by iterating over a list of dynamically registered handlers and calling all of them until one handles the exception. This is the only generic way to handle software stepping handlers in arm64 as the exception does not provide an immediate that could be checked, contrary to software breakpoints. However, the registration mechanism is not exported and has only two current users : the KGDB stepping handler, and the uprobe single step handler. Given that one comes from user mode and the other from kernel mode, call the appropriate one by checking the source EL of the exception. Add a stand-in that returns DBG_HOOK_ERROR when the configuration options are not enabled. Remove `arch_init_uprobes()` as it is not useful anymore and is specific to arm64. Unify the naming of the handler to XXX_single_step_handler(), making it clear they are related. Signed-off-by: Ada Couprie Diaz <[email protected]> Tested-by: Luis Claudio R. Goncalves <[email protected]> Reviewed-by: Will Deacon <[email protected]> Acked-by: Mark Rutland <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 6adfdc5 commit 403b48a

File tree

5 files changed

+28
-47
lines changed

5 files changed

+28
-47
lines changed

arch/arm64/include/asm/kgdb.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ extern int kgdb_fault_expected;
2626

2727
int kgdb_brk_handler(struct pt_regs *regs, unsigned long esr);
2828
int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr);
29+
#ifdef CONFIG_KGDB
30+
int kgdb_single_step_handler(struct pt_regs *regs, unsigned long esr);
31+
#else
32+
static inline int kgdb_single_step_handler(struct pt_regs *regs,
33+
unsigned long esr)
34+
{
35+
return DBG_HOOK_ERROR;
36+
}
37+
#endif
2938

3039
#endif /* !__ASSEMBLY__ */
3140

arch/arm64/include/asm/uprobes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,14 @@ struct arch_uprobe {
2929
};
3030

3131
int uprobe_brk_handler(struct pt_regs *regs, unsigned long esr);
32+
#ifdef CONFIG_UPROBES
33+
int uprobe_single_step_handler(struct pt_regs *regs, unsigned long esr);
34+
#else
35+
static inline int uprobe_single_step_handler(struct pt_regs *regs,
36+
unsigned long esr)
37+
{
38+
return DBG_HOOK_ERROR;
39+
}
40+
#endif
3241

3342
#endif

arch/arm64/kernel/debug-monitors.c

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -200,30 +200,17 @@ void unregister_kernel_step_hook(struct step_hook *hook)
200200
}
201201

202202
/*
203-
* Call registered single step handlers
203+
* Call single step handlers
204204
* There is no Syndrome info to check for determining the handler.
205-
* So we call all the registered handlers, until the right handler is
206-
* found which returns zero.
205+
* However, there is only one possible handler for user and kernel modes, so
206+
* check and call the appropriate one.
207207
*/
208208
static int call_step_hook(struct pt_regs *regs, unsigned long esr)
209209
{
210-
struct step_hook *hook;
211-
struct list_head *list;
212-
int retval = DBG_HOOK_ERROR;
210+
if (user_mode(regs))
211+
return uprobe_single_step_handler(regs, esr);
213212

214-
list = user_mode(regs) ? &user_step_hook : &kernel_step_hook;
215-
216-
/*
217-
* Since single-step exception disables interrupt, this function is
218-
* entirely not preemptible, and we can use rcu list safely here.
219-
*/
220-
list_for_each_entry_rcu(hook, list, node) {
221-
retval = hook->fn(regs, esr);
222-
if (retval == DBG_HOOK_HANDLED)
223-
break;
224-
}
225-
226-
return retval;
213+
return kgdb_single_step_handler(regs, esr);
227214
}
228215
NOKPROBE_SYMBOL(call_step_hook);
229216

arch/arm64/kernel/kgdb.c

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -250,19 +250,15 @@ int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr)
250250
}
251251
NOKPROBE_SYMBOL(kgdb_compiled_brk_handler);
252252

253-
static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned long esr)
253+
int kgdb_single_step_handler(struct pt_regs *regs, unsigned long esr)
254254
{
255255
if (!kgdb_single_step)
256256
return DBG_HOOK_ERROR;
257257

258258
kgdb_handle_exception(0, SIGTRAP, 0, regs);
259259
return DBG_HOOK_HANDLED;
260260
}
261-
NOKPROBE_SYMBOL(kgdb_step_brk_fn);
262-
263-
static struct step_hook kgdb_step_hook = {
264-
.fn = kgdb_step_brk_fn
265-
};
261+
NOKPROBE_SYMBOL(kgdb_single_step_handler);
266262

267263
static int __kgdb_notify(struct die_args *args, unsigned long cmd)
268264
{
@@ -301,13 +297,7 @@ static struct notifier_block kgdb_notifier = {
301297
*/
302298
int kgdb_arch_init(void)
303299
{
304-
int ret = register_die_notifier(&kgdb_notifier);
305-
306-
if (ret != 0)
307-
return ret;
308-
309-
register_kernel_step_hook(&kgdb_step_hook);
310-
return 0;
300+
return register_die_notifier(&kgdb_notifier);
311301
}
312302

313303
/*
@@ -317,7 +307,6 @@ int kgdb_arch_init(void)
317307
*/
318308
void kgdb_arch_exit(void)
319309
{
320-
unregister_kernel_step_hook(&kgdb_step_hook);
321310
unregister_die_notifier(&kgdb_notifier);
322311
}
323312

arch/arm64/kernel/probes/uprobes.c

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ int uprobe_brk_handler(struct pt_regs *regs,
182182
return DBG_HOOK_ERROR;
183183
}
184184

185-
static int uprobe_single_step_handler(struct pt_regs *regs,
185+
int uprobe_single_step_handler(struct pt_regs *regs,
186186
unsigned long esr)
187187
{
188188
struct uprobe_task *utask = current->utask;
@@ -194,16 +194,3 @@ static int uprobe_single_step_handler(struct pt_regs *regs,
194194
return DBG_HOOK_ERROR;
195195
}
196196

197-
/* uprobe single step handler hook */
198-
static struct step_hook uprobes_step_hook = {
199-
.fn = uprobe_single_step_handler,
200-
};
201-
202-
static int __init arch_init_uprobes(void)
203-
{
204-
register_user_step_hook(&uprobes_step_hook);
205-
206-
return 0;
207-
}
208-
209-
device_initcall(arch_init_uprobes);

0 commit comments

Comments
 (0)