Merge branch 'video' into release
[pandora-kernel.git] / arch / sh / kernel / dwarf.c
index db02136..bc4d8d7 100644 (file)
  *
  * TODO:
  *     - DWARF64 doesn't work.
+ *     - Registers with DWARF_VAL_OFFSET rules aren't handled properly.
  */
 
 /* #define DEBUG */
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/list.h>
+#include <linux/mempool.h>
 #include <linux/mm.h>
 #include <asm/dwarf.h>
 #include <asm/unwinder.h>
 #include <asm/dwarf.h>
 #include <asm/stacktrace.h>
 
+/* Reserve enough memory for two stack frames */
+#define DWARF_FRAME_MIN_REQ    2
+/* ... with 4 registers per frame. */
+#define DWARF_REG_MIN_REQ      (DWARF_FRAME_MIN_REQ * 4)
+
+static struct kmem_cache *dwarf_frame_cachep;
+static mempool_t *dwarf_frame_pool;
+
+static struct kmem_cache *dwarf_reg_cachep;
+static mempool_t *dwarf_reg_pool;
+
 static LIST_HEAD(dwarf_cie_list);
-DEFINE_SPINLOCK(dwarf_cie_lock);
+static DEFINE_SPINLOCK(dwarf_cie_lock);
 
 static LIST_HEAD(dwarf_fde_list);
-DEFINE_SPINLOCK(dwarf_fde_lock);
+static DEFINE_SPINLOCK(dwarf_fde_lock);
 
 static struct dwarf_cie *cached_cie;
 
-/*
- * Figure out whether we need to allocate some dwarf registers. If dwarf
- * registers have already been allocated then we may need to realloc
- * them. "reg" is a register number that we need to be able to access
- * after this call.
+/**
+ *     dwarf_frame_alloc_reg - allocate memory for a DWARF register
+ *     @frame: the DWARF frame whose list of registers we insert on
+ *     @reg_num: the register number
  *
- * Register numbers start at zero, therefore we need to allocate space
- * for "reg" + 1 registers.
+ *     Allocate space for, and initialise, a dwarf reg from
+ *     dwarf_reg_pool and insert it onto the (unsorted) linked-list of
+ *     dwarf registers for @frame.
+ *
+ *     Return the initialised DWARF reg.
  */
-static void dwarf_frame_alloc_regs(struct dwarf_frame *frame,
-                                  unsigned int reg)
+static struct dwarf_reg *dwarf_frame_alloc_reg(struct dwarf_frame *frame,
+                                              unsigned int reg_num)
 {
-       struct dwarf_reg *regs;
-       unsigned int num_regs = reg + 1;
-       size_t new_size;
-       size_t old_size;
-
-       new_size = num_regs * sizeof(*regs);
-       old_size = frame->num_regs * sizeof(*regs);
+       struct dwarf_reg *reg;
 
-       /* Fast path: don't allocate any regs if we've already got enough. */
-       if (frame->num_regs >= num_regs)
-               return;
-
-       regs = kzalloc(new_size, GFP_ATOMIC);
-       if (!regs) {
-               printk(KERN_WARNING "Unable to allocate DWARF registers\n");
+       reg = mempool_alloc(dwarf_reg_pool, GFP_ATOMIC);
+       if (!reg) {
+               printk(KERN_WARNING "Unable to allocate a DWARF register\n");
                /*
                 * Let's just bomb hard here, we have no way to
                 * gracefully recover.
                 */
-               BUG();
+               UNWINDER_BUG();
+       }
+
+       reg->number = reg_num;
+       reg->addr = 0;
+       reg->flags = 0;
+
+       list_add(&reg->link, &frame->reg_list);
+
+       return reg;
+}
+
+static void dwarf_frame_free_regs(struct dwarf_frame *frame)
+{
+       struct dwarf_reg *reg, *n;
+
+       list_for_each_entry_safe(reg, n, &frame->reg_list, link) {
+               list_del(&reg->link);
+               mempool_free(reg, dwarf_reg_pool);
        }
+}
+
+/**
+ *     dwarf_frame_reg - return a DWARF register
+ *     @frame: the DWARF frame to search in for @reg_num
+ *     @reg_num: the register number to search for
+ *
+ *     Lookup and return the dwarf reg @reg_num for this frame. Return
+ *     NULL if @reg_num is an register invalid number.
+ */
+static struct dwarf_reg *dwarf_frame_reg(struct dwarf_frame *frame,
+                                        unsigned int reg_num)
+{
+       struct dwarf_reg *reg;
 
-       if (frame->regs) {
-               memcpy(regs, frame->regs, old_size);
-               kfree(frame->regs);
+       list_for_each_entry(reg, &frame->reg_list, link) {
+               if (reg->number == reg_num)
+                       return reg;
        }
 
-       frame->regs = regs;
-       frame->num_regs = num_regs;
+       return NULL;
 }
 
 /**
@@ -196,7 +232,7 @@ static int dwarf_read_encoded_value(char *addr, unsigned long *val,
                break;
        default:
                pr_debug("encoding=0x%x\n", (encoding & 0x70));
-               BUG();
+               UNWINDER_BUG();
        }
 
        if ((encoding & 0x07) == 0x00)
@@ -211,7 +247,7 @@ static int dwarf_read_encoded_value(char *addr, unsigned long *val,
                break;
        default:
                pr_debug("encoding=0x%x\n", encoding);
-               BUG();
+               UNWINDER_BUG();
        }
 
        return count;
@@ -264,7 +300,7 @@ static inline int dwarf_entry_len(char *addr, unsigned long *len)
  */
 static struct dwarf_cie *dwarf_lookup_cie(unsigned long cie_ptr)
 {
-       struct dwarf_cie *cie, *n;
+       struct dwarf_cie *cie;
        unsigned long flags;
 
        spin_lock_irqsave(&dwarf_cie_lock, flags);
@@ -278,7 +314,7 @@ static struct dwarf_cie *dwarf_lookup_cie(unsigned long cie_ptr)
                goto out;
        }
 
-       list_for_each_entry_safe(cie, n, &dwarf_cie_list, link) {
+       list_for_each_entry(cie, &dwarf_cie_list, link) {
                if (cie->cie_pointer == cie_ptr) {
                        cached_cie = cie;
                        break;
@@ -299,11 +335,12 @@ out:
  */
 struct dwarf_fde *dwarf_lookup_fde(unsigned long pc)
 {
+       struct dwarf_fde *fde;
        unsigned long flags;
-       struct dwarf_fde *fde, *n;
 
        spin_lock_irqsave(&dwarf_fde_lock, flags);
-       list_for_each_entry_safe(fde, n, &dwarf_fde_list, link) {
+
+       list_for_each_entry(fde, &dwarf_fde_list, link) {
                unsigned long start, end;
 
                start = fde->initial_location;
@@ -330,7 +367,6 @@ struct dwarf_fde *dwarf_lookup_fde(unsigned long pc)
  *     @fde: the FDE for this function
  *     @frame: the instructions calculate the CFA for this frame
  *     @pc: the program counter of the address we're interested in
- *     @define_ra: keep executing insns until the return addr reg is defined?
  *
  *     Execute the Call Frame instruction sequence starting at
  *     @insn_start and ending at @insn_end. The instructions describe
@@ -342,36 +378,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
                                   struct dwarf_cie *cie,
                                   struct dwarf_fde *fde,
                                   struct dwarf_frame *frame,
-                                  unsigned long pc,
-                                  bool define_ra)
+                                  unsigned long pc)
 {
        unsigned char insn;
        unsigned char *current_insn;
        unsigned int count, delta, reg, expr_len, offset;
-       bool seen_ra_reg;
+       struct dwarf_reg *regp;
 
        current_insn = insn_start;
 
-       /*
-        * If we're executing instructions for the dwarf_unwind_stack()
-        * FDE we need to keep executing instructions until the value of
-        * DWARF_ARCH_RA_REG is defined. See the comment in
-        * dwarf_unwind_stack() for more details.
-        */
-       if (define_ra)
-               seen_ra_reg = false;
-       else
-               seen_ra_reg = true;
-
-       while (current_insn < insn_end && (frame->pc <= pc || !seen_ra_reg) ) {
+       while (current_insn < insn_end && frame->pc <= pc) {
                insn = __raw_readb(current_insn++);
 
-               if (!seen_ra_reg) {
-                       if (frame->num_regs >= DWARF_ARCH_RA_REG &&
-                           frame->regs[DWARF_ARCH_RA_REG].flags)
-                               seen_ra_reg = true;
-               }
-
                /*
                 * Firstly, handle the opcodes that embed their operands
                 * in the instructions.
@@ -388,9 +406,9 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
                        count = dwarf_read_uleb128(current_insn, &offset);
                        current_insn += count;
                        offset *= cie->data_alignment_factor;
-                       dwarf_frame_alloc_regs(frame, reg);
-                       frame->regs[reg].addr = offset;
-                       frame->regs[reg].flags |= DWARF_REG_OFFSET;
+                       regp = dwarf_frame_alloc_reg(frame, reg);
+                       regp->addr = offset;
+                       regp->flags |= DWARF_REG_OFFSET;
                        continue;
                        /* NOTREACHED */
                case DW_CFA_restore:
@@ -434,6 +452,8 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
                case DW_CFA_undefined:
                        count = dwarf_read_uleb128(current_insn, &reg);
                        current_insn += count;
+                       regp = dwarf_frame_alloc_reg(frame, reg);
+                       regp->flags |= DWARF_UNDEFINED;
                        break;
                case DW_CFA_def_cfa:
                        count = dwarf_read_uleb128(current_insn,
@@ -472,20 +492,36 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
                        count = dwarf_read_leb128(current_insn, &offset);
                        current_insn += count;
                        offset *= cie->data_alignment_factor;
-                       dwarf_frame_alloc_regs(frame, reg);
-                       frame->regs[reg].flags |= DWARF_REG_OFFSET;
-                       frame->regs[reg].addr = offset;
+                       regp = dwarf_frame_alloc_reg(frame, reg);
+                       regp->flags |= DWARF_REG_OFFSET;
+                       regp->addr = offset;
                        break;
                case DW_CFA_val_offset:
                        count = dwarf_read_uleb128(current_insn, &reg);
                        current_insn += count;
                        count = dwarf_read_leb128(current_insn, &offset);
                        offset *= cie->data_alignment_factor;
-                       frame->regs[reg].flags |= DWARF_REG_OFFSET;
-                       frame->regs[reg].addr = offset;
+                       regp = dwarf_frame_alloc_reg(frame, reg);
+                       regp->flags |= DWARF_VAL_OFFSET;
+                       regp->addr = offset;
+                       break;
+               case DW_CFA_GNU_args_size:
+                       count = dwarf_read_uleb128(current_insn, &offset);
+                       current_insn += count;
+                       break;
+               case DW_CFA_GNU_negative_offset_extended:
+                       count = dwarf_read_uleb128(current_insn, &reg);
+                       current_insn += count;
+                       count = dwarf_read_uleb128(current_insn, &offset);
+                       offset *= cie->data_alignment_factor;
+
+                       regp = dwarf_frame_alloc_reg(frame, reg);
+                       regp->flags |= DWARF_REG_OFFSET;
+                       regp->addr = -offset;
                        break;
                default:
                        pr_debug("unhandled DWARF instruction 0x%x\n", insn);
+                       UNWINDER_BUG();
                        break;
                }
        }
@@ -502,40 +538,36 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
  *     on the callstack. Each of the lower (older) stack frames are
  *     linked via the "prev" member.
  */
-struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
-                                      struct dwarf_frame *prev)
+struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
+                                       struct dwarf_frame *prev)
 {
        struct dwarf_frame *frame;
        struct dwarf_cie *cie;
        struct dwarf_fde *fde;
+       struct dwarf_reg *reg;
        unsigned long addr;
-       int i, offset;
-       bool define_ra = false;
 
        /*
         * If this is the first invocation of this recursive function we
         * need get the contents of a physical register to get the CFA
         * in order to begin the virtual unwinding of the stack.
         *
-        * Setting "define_ra" to true indictates that we want
-        * dwarf_cfa_execute_insns() to continue executing instructions
-        * until we know how to calculate the value of DWARF_ARCH_RA_REG
-        * (which we need in order to kick off the whole unwinding
-        * process).
-        *
         * NOTE: the return address is guaranteed to be setup by the
         * time this function makes its first function call.
         */
-       if (!pc && !prev) {
-               pc = (unsigned long)&dwarf_unwind_stack;
-               define_ra = true;
-       }
+       if (!pc && !prev)
+               pc = (unsigned long)current_text_addr();
 
-       frame = kzalloc(sizeof(*frame), GFP_ATOMIC);
-       if (!frame)
-               return NULL;
+       frame = mempool_alloc(dwarf_frame_pool, GFP_ATOMIC);
+       if (!frame) {
+               printk(KERN_ERR "Unable to allocate a dwarf frame\n");
+               UNWINDER_BUG();
+       }
 
+       INIT_LIST_HEAD(&frame->reg_list);
+       frame->flags = 0;
        frame->prev = prev;
+       frame->return_addr = 0;
 
        fde = dwarf_lookup_fde(pc);
        if (!fde) {
@@ -555,7 +587,7 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
                 *      case above, which sucks because we could print a
                 *      warning here.
                 */
-               return NULL;
+               goto bail;
        }
 
        cie = dwarf_lookup_cie(fde->cie_pointer);
@@ -565,20 +597,21 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
        /* CIE initial instructions */
        dwarf_cfa_execute_insns(cie->initial_instructions,
                                cie->instructions_end, cie, fde,
-                               frame, pc, false);
+                               frame, pc);
 
        /* FDE instructions */
        dwarf_cfa_execute_insns(fde->instructions, fde->end, cie,
-                               fde, frame, pc, define_ra);
+                               fde, frame, pc);
 
        /* Calculate the CFA */
        switch (frame->flags) {
        case DWARF_FRAME_CFA_REG_OFFSET:
                if (prev) {
-                       BUG_ON(!prev->regs[frame->cfa_register].flags);
+                       reg = dwarf_frame_reg(prev, frame->cfa_register);
+                       UNWINDER_BUG_ON(!reg);
+                       UNWINDER_BUG_ON(reg->flags != DWARF_REG_OFFSET);
 
-                       addr = prev->cfa;
-                       addr += prev->regs[frame->cfa_register].addr;
+                       addr = prev->cfa + reg->addr;
                        frame->cfa = __raw_readl(addr);
 
                } else {
@@ -595,27 +628,30 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
                frame->cfa += frame->cfa_offset;
                break;
        default:
-               BUG();
+               UNWINDER_BUG();
        }
 
-       /* If we haven't seen the return address reg, we're screwed. */
-       BUG_ON(!frame->regs[DWARF_ARCH_RA_REG].flags);
+       reg = dwarf_frame_reg(frame, DWARF_ARCH_RA_REG);
 
-       for (i = 0; i <= frame->num_regs; i++) {
-               struct dwarf_reg *reg = &frame->regs[i];
-
-               if (!reg->flags)
-                       continue;
+       /*
+        * If we haven't seen the return address register or the return
+        * address column is undefined then we must assume that this is
+        * the end of the callstack.
+        */
+       if (!reg || reg->flags == DWARF_UNDEFINED)
+               goto bail;
 
-               offset = reg->addr;
-               offset += frame->cfa;
-       }
+       UNWINDER_BUG_ON(reg->flags != DWARF_REG_OFFSET);
 
-       addr = frame->cfa + frame->regs[DWARF_ARCH_RA_REG].addr;
+       addr = frame->cfa + reg->addr;
        frame->return_addr = __raw_readl(addr);
 
-       frame->next = dwarf_unwind_stack(frame->return_addr, frame);
        return frame;
+
+bail:
+       dwarf_frame_free_regs(frame);
+       mempool_free(frame, dwarf_frame_pool);
+       return NULL;
 }
 
 static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
@@ -640,7 +676,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
        cie->cie_pointer = (unsigned long)entry;
 
        cie->version = *(char *)p++;
-       BUG_ON(cie->version != 1);
+       UNWINDER_BUG_ON(cie->version != 1);
 
        cie->augmentation = p;
        p += strlen(cie->augmentation) + 1;
@@ -670,7 +706,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
                count = dwarf_read_uleb128(p, &length);
                p += count;
 
-               BUG_ON((unsigned char *)p > end);
+               UNWINDER_BUG_ON((unsigned char *)p > end);
 
                cie->initial_instructions = p + length;
                cie->augmentation++;
@@ -698,16 +734,16 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
                         * routine in the CIE
                         * augmentation.
                         */
-                       BUG();
+                       UNWINDER_BUG();
                } else if (*cie->augmentation == 'S') {
-                       BUG();
+                       UNWINDER_BUG();
                } else {
                        /*
                         * Unknown augmentation. Assume
                         * 'z' augmentation.
                         */
                        p = cie->initial_instructions;
-                       BUG_ON(!p);
+                       UNWINDER_BUG_ON(!p);
                        break;
                }
        }
@@ -724,7 +760,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
 }
 
 static int dwarf_parse_fde(void *entry, u32 entry_type,
-                          void *start, unsigned long len)
+                          void *start, unsigned long len,
+                          unsigned char *end)
 {
        struct dwarf_fde *fde;
        struct dwarf_cie *cie;
@@ -771,7 +808,7 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
 
        /* Call frame instructions. */
        fde->instructions = p;
-       fde->end = start + len;
+       fde->end = end;
 
        /* Add to list. */
        spin_lock_irqsave(&dwarf_fde_lock, flags);
@@ -781,17 +818,33 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
        return 0;
 }
 
-static void dwarf_unwinder_dump(struct task_struct *task, struct pt_regs *regs,
+static void dwarf_unwinder_dump(struct task_struct *task,
+                               struct pt_regs *regs,
                                unsigned long *sp,
-                               const struct stacktrace_ops *ops, void *data)
+                               const struct stacktrace_ops *ops,
+                               void *data)
 {
-       struct dwarf_frame *frame;
+       struct dwarf_frame *frame, *_frame;
+       unsigned long return_addr;
+
+       _frame = NULL;
+       return_addr = 0;
 
-       frame = dwarf_unwind_stack(0, NULL);
+       while (1) {
+               frame = dwarf_unwind_stack(return_addr, _frame);
 
-       while (frame && frame->return_addr) {
-               ops->address(data, frame->return_addr, 1);
-               frame = frame->next;
+               if (_frame) {
+                       dwarf_frame_free_regs(_frame);
+                       mempool_free(_frame, dwarf_frame_pool);
+               }
+
+               _frame = frame;
+
+               if (!frame || !frame->return_addr)
+                       break;
+
+               return_addr = frame->return_addr;
+               ops->address(data, return_addr, 1);
        }
 }
 
@@ -803,24 +856,22 @@ static struct unwinder dwarf_unwinder = {
 
 static void dwarf_unwinder_cleanup(void)
 {
-       struct dwarf_cie *cie, *m;
-       struct dwarf_fde *fde, *n;
-       unsigned long flags;
+       struct dwarf_cie *cie;
+       struct dwarf_fde *fde;
 
        /*
         * Deallocate all the memory allocated for the DWARF unwinder.
         * Traverse all the FDE/CIE lists and remove and free all the
         * memory associated with those data structures.
         */
-       spin_lock_irqsave(&dwarf_cie_lock, flags);
-       list_for_each_entry_safe(cie, m, &dwarf_cie_list, link)
+       list_for_each_entry(cie, &dwarf_cie_list, link)
                kfree(cie);
-       spin_unlock_irqrestore(&dwarf_cie_lock, flags);
 
-       spin_lock_irqsave(&dwarf_fde_lock, flags);
-       list_for_each_entry_safe(fde, n, &dwarf_fde_list, link)
+       list_for_each_entry(fde, &dwarf_fde_list, link)
                kfree(fde);
-       spin_unlock_irqrestore(&dwarf_fde_lock, flags);
+
+       kmem_cache_destroy(dwarf_reg_cachep);
+       kmem_cache_destroy(dwarf_frame_cachep);
 }
 
 /**
@@ -832,11 +883,11 @@ static void dwarf_unwinder_cleanup(void)
  *     easy to lookup the FDE for a given PC, so we build a list of FDE
  *     and CIE entries that make it easier.
  */
-void dwarf_unwinder_init(void)
+static int __init dwarf_unwinder_init(void)
 {
        u32 entry_type;
        void *p, *entry;
-       int count, err;
+       int count, err = 0;
        unsigned long len;
        unsigned int c_entries, f_entries;
        unsigned char *end;
@@ -847,6 +898,24 @@ void dwarf_unwinder_init(void)
        f_entries = 0;
        entry = &__start_eh_frame;
 
+       dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
+                       sizeof(struct dwarf_frame), 0,
+                       SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+       dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
+                       sizeof(struct dwarf_reg), 0,
+                       SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+       dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
+                                         mempool_alloc_slab,
+                                         mempool_free_slab,
+                                         dwarf_frame_cachep);
+
+       dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
+                                        mempool_alloc_slab,
+                                        mempool_free_slab,
+                                        dwarf_reg_cachep);
+
        while ((char *)entry < __stop_eh_frame) {
                p = entry;
 
@@ -876,7 +945,7 @@ void dwarf_unwinder_init(void)
                        else
                                c_entries++;
                } else {
-                       err = dwarf_parse_fde(entry, entry_type, p, len);
+                       err = dwarf_parse_fde(entry, entry_type, p, len, end);
                        if (err < 0)
                                goto out;
                        else
@@ -893,9 +962,11 @@ void dwarf_unwinder_init(void)
        if (err)
                goto out;
 
-       return;
+       return 0;
 
 out:
        printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
        dwarf_unwinder_cleanup();
+       return -EINVAL;
 }
+early_initcall(dwarf_unwinder_init);