root/arch/parisc/kernel/unwind.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_unwind_entry_in_table
  2. find_unwind_entry
  3. unwind_table_init
  4. cmp_unwind_table_entry
  5. unwind_table_sort
  6. unwind_table_add
  7. unwind_table_remove
  8. unwind_init
  9. unwind_special
  10. unwind_frame_regs
  11. unwind_frame_init
  12. unwind_frame_init_from_blocked_task
  13. unwind_frame_init_task
  14. unwind_once
  15. unwind_to_user
  16. return_address

   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 
  34 extern struct unwind_table_entry __start___unwind[];
  35 extern struct unwind_table_entry __stop___unwind[];
  36 
  37 static 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  */
  43 static struct unwind_table kernel_unwind_table __ro_after_init;
  44 static LIST_HEAD(unwind_tables);
  45 
  46 static inline const struct unwind_table_entry *
  47 find_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 
  69 static const struct unwind_table_entry *
  70 find_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 
  98 static void
  99 unwind_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 
 128 static 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 
 134 static void
 135 unwind_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 
 142 struct unwind_table *
 143 unwind_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 
 165 void 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 */
 177 int __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 
 206 static 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 
 266 static 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 
 379 void 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 
 393 void 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 
 414 void 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 
 435 int 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 
 455 int 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 
 466 unsigned 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 }

/* [<][>][^][v][top][bottom][index][help] */