linux/arch/arm/kernel/unwind.c
<<
>>
Prefs
   1/*
   2 * arch/arm/kernel/unwind.c
   3 *
   4 * Copyright (C) 2008 ARM Limited
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18 *
  19 *
  20 * Stack unwinding support for ARM
  21 *
  22 * An ARM EABI version of gcc is required to generate the unwind
  23 * tables. For information about the structure of the unwind tables,
  24 * see "Exception Handling ABI for the ARM Architecture" at:
  25 *
  26 * http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html
  27 */
  28
  29#if !defined (__ARM_EABI__)
  30#warning Your compiler does not have EABI support.
  31#warning    ARM unwind is known to compile only with EABI compilers.
  32#warning    Change compiler or disable ARM_UNWIND option.
  33#elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2)
  34#warning Your compiler is too buggy; it is known to not compile ARM unwind support.
  35#warning    Change compiler or disable ARM_UNWIND option.
  36#endif
  37
  38#include <linux/kernel.h>
  39#include <linux/init.h>
  40#include <linux/module.h>
  41#include <linux/sched.h>
  42#include <linux/slab.h>
  43#include <linux/spinlock.h>
  44#include <linux/list.h>
  45
  46#include <asm/stacktrace.h>
  47#include <asm/traps.h>
  48#include <asm/unwind.h>
  49
  50/* Dummy functions to avoid linker complaints */
  51void __aeabi_unwind_cpp_pr0(void)
  52{
  53};
  54EXPORT_SYMBOL(__aeabi_unwind_cpp_pr0);
  55
  56void __aeabi_unwind_cpp_pr1(void)
  57{
  58};
  59EXPORT_SYMBOL(__aeabi_unwind_cpp_pr1);
  60
  61void __aeabi_unwind_cpp_pr2(void)
  62{
  63};
  64EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
  65
  66struct unwind_ctrl_block {
  67        unsigned long vrs[16];          /* virtual register set */
  68        unsigned long *insn;            /* pointer to the current instructions word */
  69        int entries;                    /* number of entries left to interpret */
  70        int byte;                       /* current byte number in the instructions word */
  71};
  72
  73enum regs {
  74#ifdef CONFIG_THUMB2_KERNEL
  75        FP = 7,
  76#else
  77        FP = 11,
  78#endif
  79        SP = 13,
  80        LR = 14,
  81        PC = 15
  82};
  83
  84extern struct unwind_idx __start_unwind_idx[];
  85extern struct unwind_idx __stop_unwind_idx[];
  86
  87static DEFINE_SPINLOCK(unwind_lock);
  88static LIST_HEAD(unwind_tables);
  89
  90/* Convert a prel31 symbol to an absolute address */
  91#define prel31_to_addr(ptr)                             \
  92({                                                      \
  93        /* sign-extend to 32 bits */                    \
  94        long offset = (((long)*(ptr)) << 1) >> 1;       \
  95        (unsigned long)(ptr) + offset;                  \
  96})
  97
  98/*
  99 * Binary search in the unwind index. The entries entries are
 100 * guaranteed to be sorted in ascending order by the linker.
 101 */
 102static struct unwind_idx *search_index(unsigned long addr,
 103                                       struct unwind_idx *first,
 104                                       struct unwind_idx *last)
 105{
 106        pr_debug("%s(%08lx, %p, %p)\n", __func__, addr, first, last);
 107
 108        if (addr < first->addr) {
 109                pr_warning("unwind: Unknown symbol address %08lx\n", addr);
 110                return NULL;
 111        } else if (addr >= last->addr)
 112                return last;
 113
 114        while (first < last - 1) {
 115                struct unwind_idx *mid = first + ((last - first + 1) >> 1);
 116
 117                if (addr < mid->addr)
 118                        last = mid;
 119                else
 120                        first = mid;
 121        }
 122
 123        return first;
 124}
 125
 126static struct unwind_idx *unwind_find_idx(unsigned long addr)
 127{
 128        struct unwind_idx *idx = NULL;
 129        unsigned long flags;
 130
 131        pr_debug("%s(%08lx)\n", __func__, addr);
 132
 133        if (core_kernel_text(addr))
 134                /* main unwind table */
 135                idx = search_index(addr, __start_unwind_idx,
 136                                   __stop_unwind_idx - 1);
 137        else {
 138                /* module unwind tables */
 139                struct unwind_table *table;
 140
 141                spin_lock_irqsave(&unwind_lock, flags);
 142                list_for_each_entry(table, &unwind_tables, list) {
 143                        if (addr >= table->begin_addr &&
 144                            addr < table->end_addr) {
 145                                idx = search_index(addr, table->start,
 146                                                   table->stop - 1);
 147                                break;
 148                        }
 149                }
 150                spin_unlock_irqrestore(&unwind_lock, flags);
 151        }
 152
 153        pr_debug("%s: idx = %p\n", __func__, idx);
 154        return idx;
 155}
 156
 157static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
 158{
 159        unsigned long ret;
 160
 161        if (ctrl->entries <= 0) {
 162                pr_warning("unwind: Corrupt unwind table\n");
 163                return 0;
 164        }
 165
 166        ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
 167
 168        if (ctrl->byte == 0) {
 169                ctrl->insn++;
 170                ctrl->entries--;
 171                ctrl->byte = 3;
 172        } else
 173                ctrl->byte--;
 174
 175        return ret;
 176}
 177
 178/*
 179 * Execute the current unwind instruction.
 180 */
 181static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
 182{
 183        unsigned long insn = unwind_get_byte(ctrl);
 184
 185        pr_debug("%s: insn = %08lx\n", __func__, insn);
 186
 187        if ((insn & 0xc0) == 0x00)
 188                ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4;
 189        else if ((insn & 0xc0) == 0x40)
 190                ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
 191        else if ((insn & 0xf0) == 0x80) {
 192                unsigned long mask;
 193                unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
 194                int load_sp, reg = 4;
 195
 196                insn = (insn << 8) | unwind_get_byte(ctrl);
 197                mask = insn & 0x0fff;
 198                if (mask == 0) {
 199                        pr_warning("unwind: 'Refuse to unwind' instruction %04lx\n",
 200                                   insn);
 201                        return -URC_FAILURE;
 202                }
 203
 204                /* pop R4-R15 according to mask */
 205                load_sp = mask & (1 << (13 - 4));
 206                while (mask) {
 207                        if (mask & 1)
 208                                ctrl->vrs[reg] = *vsp++;
 209                        mask >>= 1;
 210                        reg++;
 211                }
 212                if (!load_sp)
 213                        ctrl->vrs[SP] = (unsigned long)vsp;
 214        } else if ((insn & 0xf0) == 0x90 &&
 215                   (insn & 0x0d) != 0x0d)
 216                ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
 217        else if ((insn & 0xf0) == 0xa0) {
 218                unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
 219                int reg;
 220
 221                /* pop R4-R[4+bbb] */
 222                for (reg = 4; reg <= 4 + (insn & 7); reg++)
 223                        ctrl->vrs[reg] = *vsp++;
 224                if (insn & 0x80)
 225                        ctrl->vrs[14] = *vsp++;
 226                ctrl->vrs[SP] = (unsigned long)vsp;
 227        } else if (insn == 0xb0) {
 228                if (ctrl->vrs[PC] == 0)
 229                        ctrl->vrs[PC] = ctrl->vrs[LR];
 230                /* no further processing */
 231                ctrl->entries = 0;
 232        } else if (insn == 0xb1) {
 233                unsigned long mask = unwind_get_byte(ctrl);
 234                unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
 235                int reg = 0;
 236
 237                if (mask == 0 || mask & 0xf0) {
 238                        pr_warning("unwind: Spare encoding %04lx\n",
 239                               (insn << 8) | mask);
 240                        return -URC_FAILURE;
 241                }
 242
 243                /* pop R0-R3 according to mask */
 244                while (mask) {
 245                        if (mask & 1)
 246                                ctrl->vrs[reg] = *vsp++;
 247                        mask >>= 1;
 248                        reg++;
 249                }
 250                ctrl->vrs[SP] = (unsigned long)vsp;
 251        } else if (insn == 0xb2) {
 252                unsigned long uleb128 = unwind_get_byte(ctrl);
 253
 254                ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
 255        } else {
 256                pr_warning("unwind: Unhandled instruction %02lx\n", insn);
 257                return -URC_FAILURE;
 258        }
 259
 260        pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__,
 261                 ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
 262
 263        return URC_OK;
 264}
 265
 266/*
 267 * Unwind a single frame starting with *sp for the symbol at *pc. It
 268 * updates the *pc and *sp with the new values.
 269 */
 270int unwind_frame(struct stackframe *frame)
 271{
 272        unsigned long high, low;
 273        struct unwind_idx *idx;
 274        struct unwind_ctrl_block ctrl;
 275
 276        /* only go to a higher address on the stack */
 277        low = frame->sp;
 278        high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE;
 279
 280        pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
 281                 frame->pc, frame->lr, frame->sp);
 282
 283        if (!kernel_text_address(frame->pc))
 284                return -URC_FAILURE;
 285
 286        idx = unwind_find_idx(frame->pc);
 287        if (!idx) {
 288                pr_warning("unwind: Index not found %08lx\n", frame->pc);
 289                return -URC_FAILURE;
 290        }
 291
 292        ctrl.vrs[FP] = frame->fp;
 293        ctrl.vrs[SP] = frame->sp;
 294        ctrl.vrs[LR] = frame->lr;
 295        ctrl.vrs[PC] = 0;
 296
 297        if (idx->insn == 1)
 298                /* can't unwind */
 299                return -URC_FAILURE;
 300        else if ((idx->insn & 0x80000000) == 0)
 301                /* prel31 to the unwind table */
 302                ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);
 303        else if ((idx->insn & 0xff000000) == 0x80000000)
 304                /* only personality routine 0 supported in the index */
 305                ctrl.insn = &idx->insn;
 306        else {
 307                pr_warning("unwind: Unsupported personality routine %08lx in the index at %p\n",
 308                           idx->insn, idx);
 309                return -URC_FAILURE;
 310        }
 311
 312        /* check the personality routine */
 313        if ((*ctrl.insn & 0xff000000) == 0x80000000) {
 314                ctrl.byte = 2;
 315                ctrl.entries = 1;
 316        } else if ((*ctrl.insn & 0xff000000) == 0x81000000) {
 317                ctrl.byte = 1;
 318                ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
 319        } else {
 320                pr_warning("unwind: Unsupported personality routine %08lx at %p\n",
 321                           *ctrl.insn, ctrl.insn);
 322                return -URC_FAILURE;
 323        }
 324
 325        while (ctrl.entries > 0) {
 326                int urc = unwind_exec_insn(&ctrl);
 327                if (urc < 0)
 328                        return urc;
 329                if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high)
 330                        return -URC_FAILURE;
 331        }
 332
 333        if (ctrl.vrs[PC] == 0)
 334                ctrl.vrs[PC] = ctrl.vrs[LR];
 335
 336        /* check for infinite loop */
 337        if (frame->pc == ctrl.vrs[PC])
 338                return -URC_FAILURE;
 339
 340        frame->fp = ctrl.vrs[FP];
 341        frame->sp = ctrl.vrs[SP];
 342        frame->lr = ctrl.vrs[LR];
 343        frame->pc = ctrl.vrs[PC];
 344
 345        return URC_OK;
 346}
 347
 348void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 349{
 350        struct stackframe frame;
 351        register unsigned long current_sp asm ("sp");
 352
 353        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 354
 355        if (!tsk)
 356                tsk = current;
 357
 358        if (regs) {
 359                frame.fp = regs->ARM_fp;
 360                frame.sp = regs->ARM_sp;
 361                frame.lr = regs->ARM_lr;
 362                frame.pc = regs->ARM_pc;
 363        } else if (tsk == current) {
 364                frame.fp = (unsigned long)__builtin_frame_address(0);
 365                frame.sp = current_sp;
 366                frame.lr = (unsigned long)__builtin_return_address(0);
 367                frame.pc = (unsigned long)unwind_backtrace;
 368        } else {
 369                /* task blocked in __switch_to */
 370                frame.fp = thread_saved_fp(tsk);
 371                frame.sp = thread_saved_sp(tsk);
 372                /*
 373                 * The function calling __switch_to cannot be a leaf function
 374                 * so LR is recovered from the stack.
 375                 */
 376                frame.lr = 0;
 377                frame.pc = thread_saved_pc(tsk);
 378        }
 379
 380        while (1) {
 381                int urc;
 382                unsigned long where = frame.pc;
 383
 384                urc = unwind_frame(&frame);
 385                if (urc < 0)
 386                        break;
 387                dump_backtrace_entry(where, frame.pc, frame.sp - 4);
 388        }
 389}
 390
 391struct unwind_table *unwind_table_add(unsigned long start, unsigned long size,
 392                                      unsigned long text_addr,
 393                                      unsigned long text_size)
 394{
 395        unsigned long flags;
 396        struct unwind_idx *idx;
 397        struct unwind_table *tab = kmalloc(sizeof(*tab), GFP_KERNEL);
 398
 399        pr_debug("%s(%08lx, %08lx, %08lx, %08lx)\n", __func__, start, size,
 400                 text_addr, text_size);
 401
 402        if (!tab)
 403                return tab;
 404
 405        tab->start = (struct unwind_idx *)start;
 406        tab->stop = (struct unwind_idx *)(start + size);
 407        tab->begin_addr = text_addr;
 408        tab->end_addr = text_addr + text_size;
 409
 410        /* Convert the symbol addresses to absolute values */
 411        for (idx = tab->start; idx < tab->stop; idx++)
 412                idx->addr = prel31_to_addr(&idx->addr);
 413
 414        spin_lock_irqsave(&unwind_lock, flags);
 415        list_add_tail(&tab->list, &unwind_tables);
 416        spin_unlock_irqrestore(&unwind_lock, flags);
 417
 418        return tab;
 419}
 420
 421void unwind_table_del(struct unwind_table *tab)
 422{
 423        unsigned long flags;
 424
 425        if (!tab)
 426                return;
 427
 428        spin_lock_irqsave(&unwind_lock, flags);
 429        list_del(&tab->list);
 430        spin_unlock_irqrestore(&unwind_lock, flags);
 431
 432        kfree(tab);
 433}
 434
 435int __init unwind_init(void)
 436{
 437        struct unwind_idx *idx;
 438
 439        /* Convert the symbol addresses to absolute values */
 440        for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++)
 441                idx->addr = prel31_to_addr(&idx->addr);
 442
 443        pr_debug("unwind: ARM stack unwinding initialised\n");
 444
 445        return 0;
 446}
 447
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.