linux/arch/s390/lib/test_unwind.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Test module for unwind_for_each_frame
   4 */
   5
   6#define pr_fmt(fmt) "test_unwind: " fmt
   7#include <asm/unwind.h>
   8#include <linux/completion.h>
   9#include <linux/kallsyms.h>
  10#include <linux/kthread.h>
  11#include <linux/module.h>
  12#include <linux/string.h>
  13#include <linux/kprobes.h>
  14#include <linux/wait.h>
  15#include <asm/irq.h>
  16#include <asm/delay.h>
  17
  18#define BT_BUF_SIZE (PAGE_SIZE * 4)
  19
  20/*
  21 * To avoid printk line limit split backtrace by lines
  22 */
  23static void print_backtrace(char *bt)
  24{
  25        char *p;
  26
  27        while (true) {
  28                p = strsep(&bt, "\n");
  29                if (!p)
  30                        break;
  31                pr_err("%s\n", p);
  32        }
  33}
  34
  35/*
  36 * Calls unwind_for_each_frame(task, regs, sp) and verifies that the result
  37 * contains unwindme_func2 followed by unwindme_func1.
  38 */
  39static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
  40                                unsigned long sp)
  41{
  42        int frame_count, prev_is_func2, seen_func2_func1;
  43        const int max_frames = 128;
  44        struct unwind_state state;
  45        size_t bt_pos = 0;
  46        int ret = 0;
  47        char *bt;
  48
  49        bt = kmalloc(BT_BUF_SIZE, GFP_ATOMIC);
  50        if (!bt) {
  51                pr_err("failed to allocate backtrace buffer\n");
  52                return -ENOMEM;
  53        }
  54        /* Unwind. */
  55        frame_count = 0;
  56        prev_is_func2 = 0;
  57        seen_func2_func1 = 0;
  58        unwind_for_each_frame(&state, task, regs, sp) {
  59                unsigned long addr = unwind_get_return_address(&state);
  60                char sym[KSYM_SYMBOL_LEN];
  61
  62                if (frame_count++ == max_frames)
  63                        break;
  64                if (state.reliable && !addr) {
  65                        pr_err("unwind state reliable but addr is 0\n");
  66                        return -EINVAL;
  67                }
  68                sprint_symbol(sym, addr);
  69                if (bt_pos < BT_BUF_SIZE) {
  70                        bt_pos += snprintf(bt + bt_pos, BT_BUF_SIZE - bt_pos,
  71                                           state.reliable ? " [%-7s%px] %pSR\n" :
  72                                                            "([%-7s%px] %pSR)\n",
  73                                           stack_type_name(state.stack_info.type),
  74                                           (void *)state.sp, (void *)state.ip);
  75                        if (bt_pos >= BT_BUF_SIZE)
  76                                pr_err("backtrace buffer is too small\n");
  77                }
  78                frame_count += 1;
  79                if (prev_is_func2 && str_has_prefix(sym, "unwindme_func1"))
  80                        seen_func2_func1 = 1;
  81                prev_is_func2 = str_has_prefix(sym, "unwindme_func2");
  82        }
  83
  84        /* Check the results. */
  85        if (unwind_error(&state)) {
  86                pr_err("unwind error\n");
  87                ret = -EINVAL;
  88        }
  89        if (!seen_func2_func1) {
  90                pr_err("unwindme_func2 and unwindme_func1 not found\n");
  91                ret = -EINVAL;
  92        }
  93        if (frame_count == max_frames) {
  94                pr_err("Maximum number of frames exceeded\n");
  95                ret = -EINVAL;
  96        }
  97        if (ret)
  98                print_backtrace(bt);
  99        kfree(bt);
 100        return ret;
 101}
 102
 103/* State of the task being unwound. */
 104struct unwindme {
 105        int flags;
 106        int ret;
 107        struct task_struct *task;
 108        struct completion task_ready;
 109        wait_queue_head_t task_wq;
 110        unsigned long sp;
 111};
 112
 113static struct unwindme *unwindme;
 114
 115/* Values of unwindme.flags. */
 116#define UWM_DEFAULT             0x0
 117#define UWM_THREAD              0x1     /* Unwind a separate task. */
 118#define UWM_REGS                0x2     /* Pass regs to test_unwind(). */
 119#define UWM_SP                  0x4     /* Pass sp to test_unwind(). */
 120#define UWM_CALLER              0x8     /* Unwind starting from caller. */
 121#define UWM_SWITCH_STACK        0x10    /* Use CALL_ON_STACK. */
 122#define UWM_IRQ                 0x20    /* Unwind from irq context. */
 123#define UWM_PGM                 0x40    /* Unwind from program check handler. */
 124
 125static __always_inline unsigned long get_psw_addr(void)
 126{
 127        unsigned long psw_addr;
 128
 129        asm volatile(
 130                "basr   %[psw_addr],0\n"
 131                : [psw_addr] "=d" (psw_addr));
 132        return psw_addr;
 133}
 134
 135#ifdef CONFIG_KPROBES
 136static int pgm_pre_handler(struct kprobe *p, struct pt_regs *regs)
 137{
 138        struct unwindme *u = unwindme;
 139
 140        u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? regs : NULL,
 141                             (u->flags & UWM_SP) ? u->sp : 0);
 142        return 0;
 143}
 144#endif
 145
 146/* This function may or may not appear in the backtrace. */
 147static noinline int unwindme_func4(struct unwindme *u)
 148{
 149        if (!(u->flags & UWM_CALLER))
 150                u->sp = current_frame_address();
 151        if (u->flags & UWM_THREAD) {
 152                complete(&u->task_ready);
 153                wait_event(u->task_wq, kthread_should_park());
 154                kthread_parkme();
 155                return 0;
 156#ifdef CONFIG_KPROBES
 157        } else if (u->flags & UWM_PGM) {
 158                struct kprobe kp;
 159                int ret;
 160
 161                unwindme = u;
 162                memset(&kp, 0, sizeof(kp));
 163                kp.symbol_name = "do_report_trap";
 164                kp.pre_handler = pgm_pre_handler;
 165                ret = register_kprobe(&kp);
 166                if (ret < 0) {
 167                        pr_err("register_kprobe failed %d\n", ret);
 168                        return -EINVAL;
 169                }
 170
 171                /*
 172                 * trigger specification exception
 173                 */
 174                asm volatile(
 175                        "       mvcl    %%r1,%%r1\n"
 176                        "0:     nopr    %%r7\n"
 177                        EX_TABLE(0b, 0b)
 178                        :);
 179
 180                unregister_kprobe(&kp);
 181                unwindme = NULL;
 182                return u->ret;
 183#endif
 184        } else {
 185                struct pt_regs regs;
 186
 187                memset(&regs, 0, sizeof(regs));
 188                regs.psw.addr = get_psw_addr();
 189                regs.gprs[15] = current_stack_pointer();
 190                return test_unwind(NULL,
 191                                   (u->flags & UWM_REGS) ? &regs : NULL,
 192                                   (u->flags & UWM_SP) ? u->sp : 0);
 193        }
 194}
 195
 196/* This function may or may not appear in the backtrace. */
 197static noinline int unwindme_func3(struct unwindme *u)
 198{
 199        u->sp = current_frame_address();
 200        return unwindme_func4(u);
 201}
 202
 203/* This function must appear in the backtrace. */
 204static noinline int unwindme_func2(struct unwindme *u)
 205{
 206        int rc;
 207
 208        if (u->flags & UWM_SWITCH_STACK) {
 209                preempt_disable();
 210                rc = CALL_ON_STACK(unwindme_func3, S390_lowcore.nodat_stack, 1, u);
 211                preempt_enable();
 212                return rc;
 213        } else {
 214                return unwindme_func3(u);
 215        }
 216}
 217
 218/* This function must follow unwindme_func2 in the backtrace. */
 219static noinline int unwindme_func1(void *u)
 220{
 221        return unwindme_func2((struct unwindme *)u);
 222}
 223
 224static void unwindme_irq_handler(struct ext_code ext_code,
 225                                       unsigned int param32,
 226                                       unsigned long param64)
 227{
 228        struct unwindme *u = READ_ONCE(unwindme);
 229
 230        if (u && u->task == current) {
 231                unwindme = NULL;
 232                u->task = NULL;
 233                u->ret = unwindme_func1(u);
 234        }
 235}
 236
 237static int test_unwind_irq(struct unwindme *u)
 238{
 239        preempt_disable();
 240        if (register_external_irq(EXT_IRQ_CLK_COMP, unwindme_irq_handler)) {
 241                pr_info("Couldn't register external interrupt handler");
 242                return -1;
 243        }
 244        u->task = current;
 245        unwindme = u;
 246        udelay(1);
 247        unregister_external_irq(EXT_IRQ_CLK_COMP, unwindme_irq_handler);
 248        preempt_enable();
 249        return u->ret;
 250}
 251
 252/* Spawns a task and passes it to test_unwind(). */
 253static int test_unwind_task(struct unwindme *u)
 254{
 255        struct task_struct *task;
 256        int ret;
 257
 258        /* Initialize thread-related fields. */
 259        init_completion(&u->task_ready);
 260        init_waitqueue_head(&u->task_wq);
 261
 262        /*
 263         * Start the task and wait until it reaches unwindme_func4() and sleeps
 264         * in (task_ready, unwind_done] range.
 265         */
 266        task = kthread_run(unwindme_func1, u, "%s", __func__);
 267        if (IS_ERR(task)) {
 268                pr_err("kthread_run() failed\n");
 269                return PTR_ERR(task);
 270        }
 271        /*
 272         * Make sure task reaches unwindme_func4 before parking it,
 273         * we might park it before kthread function has been executed otherwise
 274         */
 275        wait_for_completion(&u->task_ready);
 276        kthread_park(task);
 277        /* Unwind. */
 278        ret = test_unwind(task, NULL, (u->flags & UWM_SP) ? u->sp : 0);
 279        kthread_stop(task);
 280        return ret;
 281}
 282
 283static int test_unwind_flags(int flags)
 284{
 285        struct unwindme u;
 286
 287        u.flags = flags;
 288        if (u.flags & UWM_THREAD)
 289                return test_unwind_task(&u);
 290        else if (u.flags & UWM_IRQ)
 291                return test_unwind_irq(&u);
 292        else
 293                return unwindme_func1(&u);
 294}
 295
 296static int test_unwind_init(void)
 297{
 298        int ret = 0;
 299
 300#define TEST(flags)                                                     \
 301do {                                                                    \
 302        pr_info("[ RUN      ] " #flags "\n");                           \
 303        if (!test_unwind_flags((flags))) {                              \
 304                pr_info("[       OK ] " #flags "\n");                   \
 305        } else {                                                        \
 306                pr_err("[  FAILED  ] " #flags "\n");                    \
 307                ret = -EINVAL;                                          \
 308        }                                                               \
 309} while (0)
 310
 311        TEST(UWM_DEFAULT);
 312        TEST(UWM_SP);
 313        TEST(UWM_REGS);
 314        TEST(UWM_SWITCH_STACK);
 315        TEST(UWM_SP | UWM_REGS);
 316        TEST(UWM_CALLER | UWM_SP);
 317        TEST(UWM_CALLER | UWM_SP | UWM_REGS);
 318        TEST(UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK);
 319        TEST(UWM_THREAD);
 320        TEST(UWM_THREAD | UWM_SP);
 321        TEST(UWM_THREAD | UWM_CALLER | UWM_SP);
 322        TEST(UWM_IRQ);
 323        TEST(UWM_IRQ | UWM_SWITCH_STACK);
 324        TEST(UWM_IRQ | UWM_SP);
 325        TEST(UWM_IRQ | UWM_REGS);
 326        TEST(UWM_IRQ | UWM_SP | UWM_REGS);
 327        TEST(UWM_IRQ | UWM_CALLER | UWM_SP);
 328        TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS);
 329        TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK);
 330#ifdef CONFIG_KPROBES
 331        TEST(UWM_PGM);
 332        TEST(UWM_PGM | UWM_SP);
 333        TEST(UWM_PGM | UWM_REGS);
 334        TEST(UWM_PGM | UWM_SP | UWM_REGS);
 335#endif
 336#undef TEST
 337
 338        return ret;
 339}
 340
 341static void test_unwind_exit(void)
 342{
 343}
 344
 345module_init(test_unwind_init);
 346module_exit(test_unwind_exit);
 347MODULE_LICENSE("GPL");
 348