linux/arch/parisc/kernel/unwind.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Kernel unwinding support
   4 *
   5 * (c) 2002-2004 Randolph Chung <tausq@debian.org>
   6 *
   7 * Derived partially from the IA64 implementation. The PA-RISC
   8 * Runtime Architecture Document is also a useful reference to
   9 * understand what is happening here
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/sched.h>
  15#include <linux/slab.h>
  16#include <linux/sort.h>
  17
  18#include <linux/uaccess.h>
  19#include <asm/assembly.h>
  20#include <asm/asm-offsets.h>
  21#include <asm/ptrace.h>
  22
  23#include <asm/unwind.h>
  24
  25/* #define DEBUG 1 */
  26#ifdef DEBUG
  27#define dbg(x...) pr_debug(x)
  28#else
  29#define dbg(x...)
  30#endif
  31
  32#define KERNEL_START (KERNEL_BINARY_TEXT_START)
  33
  34extern struct unwind_table_entry __start___unwind[];
  35extern struct unwind_table_entry __stop___unwind[];
  36
  37static DEFINE_SPINLOCK(unwind_lock);
  38/*
  39 * the kernel unwind block is not dynamically allocated so that
  40 * we can call unwind_init as early in the bootup process as 
  41 * possible (before the slab allocator is initialized)
  42 */
  43static struct unwind_table kernel_unwind_table __ro_after_init;
  44static LIST_HEAD(unwind_tables);
  45
  46static inline const struct unwind_table_entry *
  47find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
  48{
  49        const struct unwind_table_entry *e = NULL;
  50        unsigned long lo, hi, mid;
  51
  52        lo = 0; 
  53        hi = table->length - 1; 
  54        
  55        while (lo <= hi) {
  56                mid = (hi - lo) / 2 + lo;
  57                e = &table->table[mid];
  58                if (addr < e->region_start)
  59                        hi = mid - 1;
  60                else if (addr > e->region_end)
  61                        lo = mid + 1;
  62                else
  63                        return e;
  64        }
  65
  66        return NULL;
  67}
  68
  69static const struct unwind_table_entry *
  70find_unwind_entry(unsigned long addr)
  71{
  72        struct unwind_table *table;
  73        const struct unwind_table_entry *e = NULL;
  74
  75        if (addr >= kernel_unwind_table.start && 
  76            addr <= kernel_unwind_table.end)
  77                e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
  78        else {
  79                unsigned long flags;
  80
  81                spin_lock_irqsave(&unwind_lock, flags);
  82                list_for_each_entry(table, &unwind_tables, list) {
  83                        if (addr >= table->start && 
  84                            addr <= table->end)
  85                                e = find_unwind_entry_in_table(table, addr);
  86                        if (e) {
  87                                /* Move-to-front to exploit common traces */
  88                                list_move(&table->list, &unwind_tables);
  89                                break;
  90                        }
  91                }
  92                spin_unlock_irqrestore(&unwind_lock, flags);
  93        }
  94
  95        return e;
  96}
  97
  98static void
  99unwind_table_init(struct unwind_table *table, const char *name,
 100                  unsigned long base_addr, unsigned long gp,
 101                  void *table_start, void *table_end)
 102{
 103        struct unwind_table_entry *start = table_start;
 104        struct unwind_table_entry *end = 
 105                (struct unwind_table_entry *)table_end - 1;
 106
 107        table->name = name;
 108        table->base_addr = base_addr;
 109        table->gp = gp;
 110        table->start = base_addr + start->region_start;
 111        table->end = base_addr + end->region_end;
 112        table->table = (struct unwind_table_entry *)table_start;
 113        table->length = end - start + 1;
 114        INIT_LIST_HEAD(&table->list);
 115
 116        for (; start <= end; start++) {
 117                if (start < end && 
 118                    start->region_end > (start+1)->region_start) {
 119                        pr_warn("Out of order unwind entry! %px and %px\n",
 120                                start, start+1);
 121                }
 122
 123                start->region_start += base_addr;
 124                start->region_end += base_addr;
 125        }
 126}
 127
 128static int cmp_unwind_table_entry(const void *a, const void *b)
 129{
 130        return ((const struct unwind_table_entry *)a)->region_start
 131             - ((const struct unwind_table_entry *)b)->region_start;
 132}
 133
 134static void
 135unwind_table_sort(struct unwind_table_entry *start,
 136                  struct unwind_table_entry *finish)
 137{
 138        sort(start, finish - start, sizeof(struct unwind_table_entry),
 139             cmp_unwind_table_entry, NULL);
 140}
 141
 142struct unwind_table *
 143unwind_table_add(const char *name, unsigned long base_addr, 
 144                 unsigned long gp,
 145                 void *start, void *end)
 146{
 147        struct unwind_table *table;
 148        unsigned long flags;
 149        struct unwind_table_entry *s = (struct unwind_table_entry *)start;
 150        struct unwind_table_entry *e = (struct unwind_table_entry *)end;
 151
 152        unwind_table_sort(s, e);
 153
 154        table = kmalloc(sizeof(struct unwind_table), GFP_USER);
 155        if (table == NULL)
 156                return NULL;
 157        unwind_table_init(table, name, base_addr, gp, start, end);
 158        spin_lock_irqsave(&unwind_lock, flags);
 159        list_add_tail(&table->list, &unwind_tables);
 160        spin_unlock_irqrestore(&unwind_lock, flags);
 161
 162        return table;
 163}
 164
 165void unwind_table_remove(struct unwind_table *table)
 166{
 167        unsigned long flags;
 168
 169        spin_lock_irqsave(&unwind_lock, flags);
 170        list_del(&table->list);
 171        spin_unlock_irqrestore(&unwind_lock, flags);
 172
 173        kfree(table);
 174}
 175
 176/* Called from setup_arch to import the kernel unwind info */
 177int __init unwind_init(void)
 178{
 179        long start, stop;
 180        register unsigned long gp __asm__ ("r27");
 181
 182        start = (long)&__start___unwind[0];
 183        stop = (long)&__stop___unwind[0];
 184
 185        dbg("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
 186            start, stop,
 187            (stop - start) / sizeof(struct unwind_table_entry));
 188
 189        unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
 190                          gp, 
 191                          &__start___unwind[0], &__stop___unwind[0]);
 192#if 0
 193        {
 194                int i;
 195                for (i = 0; i < 10; i++)
 196                {
 197                        printk("region 0x%x-0x%x\n", 
 198                                __start___unwind[i].region_start, 
 199                                __start___unwind[i].region_end);
 200                }
 201        }
 202#endif
 203        return 0;
 204}
 205
 206static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
 207{
 208        /*
 209         * We have to use void * instead of a function pointer, because
 210         * function pointers aren't a pointer to the function on 64-bit.
 211         * Make them const so the compiler knows they live in .text
 212         * Note: We could use dereference_kernel_function_descriptor()
 213         * instead but we want to keep it simple here.
 214         */
 215        extern void * const handle_interruption;
 216        extern void * const ret_from_kernel_thread;
 217        extern void * const syscall_exit;
 218        extern void * const intr_return;
 219        extern void * const _switch_to_ret;
 220#ifdef CONFIG_IRQSTACKS
 221        extern void * const _call_on_stack;
 222#endif /* CONFIG_IRQSTACKS */
 223
 224        if (pc == (unsigned long) &handle_interruption) {
 225                struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
 226                dbg("Unwinding through handle_interruption()\n");
 227                info->prev_sp = regs->gr[30];
 228                info->prev_ip = regs->iaoq[0];
 229                return 1;
 230        }
 231
 232        if (pc == (unsigned long) &ret_from_kernel_thread ||
 233            pc == (unsigned long) &syscall_exit) {
 234                info->prev_sp = info->prev_ip = 0;
 235                return 1;
 236        }
 237
 238        if (pc == (unsigned long) &intr_return) {
 239                struct pt_regs *regs;
 240
 241                dbg("Found intr_return()\n");
 242                regs = (struct pt_regs *)(info->sp - PT_SZ_ALGN);
 243                info->prev_sp = regs->gr[30];
 244                info->prev_ip = regs->iaoq[0];
 245                info->rp = regs->gr[2];
 246                return 1;
 247        }
 248
 249        if (pc == (unsigned long) &_switch_to_ret) {
 250                info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
 251                info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
 252                return 1;
 253        }
 254
 255#ifdef CONFIG_IRQSTACKS
 256        if (pc == (unsigned long) &_call_on_stack) {
 257                info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
 258                info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
 259                return 1;
 260        }
 261#endif
 262
 263        return 0;
 264}
 265
 266static void unwind_frame_regs(struct unwind_frame_info *info)
 267{
 268        const struct unwind_table_entry *e;
 269        unsigned long npc;
 270        unsigned int insn;
 271        long frame_size = 0;
 272        int looking_for_rp, rpoffset = 0;
 273
 274        e = find_unwind_entry(info->ip);
 275        if (e == NULL) {
 276                unsigned long sp;
 277
 278                dbg("Cannot find unwind entry for %pS; forced unwinding\n",
 279                        (void *) info->ip);
 280
 281                /* Since we are doing the unwinding blind, we don't know if
 282                   we are adjusting the stack correctly or extracting the rp
 283                   correctly. The rp is checked to see if it belongs to the
 284                   kernel text section, if not we assume we don't have a 
 285                   correct stack frame and we continue to unwind the stack.
 286                   This is not quite correct, and will fail for loadable
 287                   modules. */
 288                sp = info->sp & ~63;
 289                do {
 290                        unsigned long tmp;
 291
 292                        info->prev_sp = sp - 64;
 293                        info->prev_ip = 0;
 294
 295                        /* The stack is at the end inside the thread_union
 296                         * struct. If we reach data, we have reached the
 297                         * beginning of the stack and should stop unwinding. */
 298                        if (info->prev_sp >= (unsigned long) task_thread_info(info->t) &&
 299                            info->prev_sp < ((unsigned long) task_thread_info(info->t)
 300                                                + THREAD_SZ_ALGN)) {
 301                                info->prev_sp = 0;
 302                                break;
 303                        }
 304
 305                        if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
 306                                break;
 307                        info->prev_ip = tmp;
 308                        sp = info->prev_sp;
 309                } while (!kernel_text_address(info->prev_ip));
 310
 311                info->rp = 0;
 312
 313                dbg("analyzing func @ %lx with no unwind info, setting "
 314                    "prev_sp=%lx prev_ip=%lx\n", info->ip, 
 315                    info->prev_sp, info->prev_ip);
 316        } else {
 317                dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
 318                    "Save_RP = %d, Millicode = %d size = %u\n", 
 319                    e->region_start, e->region_end, e->Save_SP, e->Save_RP, 
 320                    e->Millicode, e->Total_frame_size);
 321
 322                looking_for_rp = e->Save_RP;
 323
 324                for (npc = e->region_start; 
 325                     (frame_size < (e->Total_frame_size << 3) || 
 326                      looking_for_rp) && 
 327                     npc < info->ip; 
 328                     npc += 4) {
 329
 330                        insn = *(unsigned int *)npc;
 331
 332                        if ((insn & 0xffffc001) == 0x37de0000 ||
 333                            (insn & 0xffe00001) == 0x6fc00000) {
 334                                /* ldo X(sp), sp, or stwm X,D(sp) */
 335                                frame_size += (insn & 0x3fff) >> 1;
 336                                dbg("analyzing func @ %lx, insn=%08x @ "
 337                                    "%lx, frame_size = %ld\n", info->ip,
 338                                    insn, npc, frame_size);
 339                        } else if ((insn & 0xffe00009) == 0x73c00008) {
 340                                /* std,ma X,D(sp) */
 341                                frame_size += ((insn >> 4) & 0x3ff) << 3;
 342                                dbg("analyzing func @ %lx, insn=%08x @ "
 343                                    "%lx, frame_size = %ld\n", info->ip,
 344                                    insn, npc, frame_size);
 345                        } else if (insn == 0x6bc23fd9) { 
 346                                /* stw rp,-20(sp) */
 347                                rpoffset = 20;
 348                                looking_for_rp = 0;
 349                                dbg("analyzing func @ %lx, insn=stw rp,"
 350                                    "-20(sp) @ %lx\n", info->ip, npc);
 351                        } else if (insn == 0x0fc212c1) {
 352                                /* std rp,-16(sr0,sp) */
 353                                rpoffset = 16;
 354                                looking_for_rp = 0;
 355                                dbg("analyzing func @ %lx, insn=std rp,"
 356                                    "-16(sp) @ %lx\n", info->ip, npc);
 357                        }
 358                }
 359
 360                if (frame_size > e->Total_frame_size << 3)
 361                        frame_size = e->Total_frame_size << 3;
 362
 363                if (!unwind_special(info, e->region_start, frame_size)) {
 364                        info->prev_sp = info->sp - frame_size;
 365                        if (e->Millicode)
 366                                info->rp = info->r31;
 367                        else if (rpoffset)
 368                                info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
 369                        info->prev_ip = info->rp;
 370                        info->rp = 0;
 371                }
 372
 373                dbg("analyzing func @ %lx, setting prev_sp=%lx "
 374                    "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
 375                    info->prev_ip, npc);
 376        }
 377}
 378
 379void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
 380                       struct pt_regs *regs)
 381{
 382        memset(info, 0, sizeof(struct unwind_frame_info));
 383        info->t = t;
 384        info->sp = regs->gr[30];
 385        info->ip = regs->iaoq[0];
 386        info->rp = regs->gr[2];
 387        info->r31 = regs->gr[31];
 388
 389        dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
 390            t ? (int)t->pid : -1, info->sp, info->ip);
 391}
 392
 393void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
 394{
 395        struct pt_regs *r = &t->thread.regs;
 396        struct pt_regs *r2;
 397
 398        r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC);
 399        if (!r2)
 400                return;
 401        *r2 = *r;
 402        r2->gr[30] = r->ksp;
 403        r2->iaoq[0] = r->kpc;
 404        unwind_frame_init(info, t, r2);
 405        kfree(r2);
 406}
 407
 408#define get_parisc_stackpointer() ({ \
 409        unsigned long sp; \
 410        __asm__("copy %%r30, %0" : "=r"(sp)); \
 411        (sp); \
 412})
 413
 414void unwind_frame_init_task(struct unwind_frame_info *info,
 415        struct task_struct *task, struct pt_regs *regs)
 416{
 417        task = task ? task : current;
 418
 419        if (task == current) {
 420                struct pt_regs r;
 421
 422                if (!regs) {
 423                        memset(&r, 0, sizeof(r));
 424                        r.iaoq[0] =  _THIS_IP_;
 425                        r.gr[2] = _RET_IP_;
 426                        r.gr[30] = get_parisc_stackpointer();
 427                        regs = &r;
 428                }
 429                unwind_frame_init(info, task, regs);
 430        } else {
 431                unwind_frame_init_from_blocked_task(info, task);
 432        }
 433}
 434
 435int unwind_once(struct unwind_frame_info *next_frame)
 436{
 437        unwind_frame_regs(next_frame);
 438
 439        if (next_frame->prev_sp == 0 ||
 440            next_frame->prev_ip == 0)
 441                return -1;
 442
 443        next_frame->sp = next_frame->prev_sp;
 444        next_frame->ip = next_frame->prev_ip;
 445        next_frame->prev_sp = 0;
 446        next_frame->prev_ip = 0;
 447
 448        dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
 449            next_frame->t ? (int)next_frame->t->pid : -1, 
 450            next_frame->sp, next_frame->ip);
 451
 452        return 0;
 453}
 454
 455int unwind_to_user(struct unwind_frame_info *info)
 456{
 457        int ret;
 458        
 459        do {
 460                ret = unwind_once(info);
 461        } while (!ret && !(info->ip & 3));
 462
 463        return ret;
 464}
 465
 466unsigned long return_address(unsigned int level)
 467{
 468        struct unwind_frame_info info;
 469
 470        /* initialize unwind info */
 471        unwind_frame_init_task(&info, current, NULL);
 472
 473        /* unwind stack */
 474        level += 2;
 475        do {
 476                if (unwind_once(&info) < 0 || info.ip == 0)
 477                        return 0;
 478                if (!kernel_text_address(info.ip))
 479                        return 0;
 480        } while (info.ip && level--);
 481
 482        return info.ip;
 483}
 484