]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'sh/dwarf-unwinder'
authorPaul Mundt <lethal@linux-sh.org>
Sun, 11 Oct 2009 23:50:07 +0000 (08:50 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Sun, 11 Oct 2009 23:50:07 +0000 (08:50 +0900)
Conflicts:
arch/sh/kernel/dwarf.c

1  2 
arch/sh/include/asm/dwarf.h
arch/sh/kernel/dwarf.c

index ced6795891a6f06977e54b9f3da239da0fdd71ae,eef87539963d09f5cf4d141e318b486794fd469c..fc51e66f2380b3097ba6c43b87f0a1177906e072
   */
  static __always_inline unsigned long dwarf_read_arch_reg(unsigned int reg)
  {
 -      unsigned long value;
 +      unsigned long value = 0;
  
        switch (reg) {
        case 14:
@@@ -241,6 -241,12 +241,12 @@@ struct dwarf_cie 
  
        unsigned long flags;
  #define DWARF_CIE_Z_AUGMENTATION      (1 << 0)
+       /*
+        * 'mod' will be non-NULL if this CIE came from a module's
+        * .eh_frame section.
+        */
+       struct module *mod;
  };
  
  /**
@@@ -255,6 -261,12 +261,12 @@@ struct dwarf_fde 
        unsigned char *instructions;
        unsigned char *end;
        struct list_head link;
+       /*
+        * 'mod' will be non-NULL if this FDE came from a module's
+        * .eh_frame section.
+        */
+       struct module *mod;
  };
  
  /**
@@@ -364,6 -376,10 +376,10 @@@ static inline unsigned int DW_CFA_opera
  
  extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
                                              struct dwarf_frame *);
+ extern void dwarf_free_frame(struct dwarf_frame *);
+ extern int dwarf_parse_section(char *, char *, struct module *);
+ extern void dwarf_module_unload(struct module *);
  #endif /* !__ASSEMBLY__ */
  
  #define CFI_STARTPROC .cfi_startproc
diff --combined arch/sh/kernel/dwarf.c
index 03b3616c80a5e164502b0d4d4a77e35831348de3,f242cd120cf1eb77c2d5786c11d972cc15fd9344..c274039e9c8d6a2f3d5683bef5f3c3143bcd141a
@@@ -24,6 -24,7 +24,6 @@@
  #include <asm/unwinder.h>
  #include <asm/sections.h>
  #include <asm/unaligned.h>
 -#include <asm/dwarf.h>
  #include <asm/stacktrace.h>
  
  /* Reserve enough memory for two stack frames */
@@@ -529,7 -530,18 +529,18 @@@ static int dwarf_cfa_execute_insns(unsi
  }
  
  /**
-  *    dwarf_unwind_stack - recursively unwind the stack
+  *    dwarf_free_frame - free the memory allocated for @frame
+  *    @frame: the frame to free
+  */
+ void dwarf_free_frame(struct dwarf_frame *frame)
+ {
+       dwarf_frame_free_regs(frame);
+       mempool_free(frame, dwarf_frame_pool);
+ }
+ /**
+  *    dwarf_unwind_stack - unwind the stack
+  *
   *    @pc: address of the function to unwind
   *    @prev: struct dwarf_frame of the previous stackframe on the callstack
   *
@@@ -547,9 -559,9 +558,9 @@@ struct dwarf_frame * dwarf_unwind_stack
        unsigned long addr;
  
        /*
-        * 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.
+        * If we're starting at the top of the stack we need get the
+        * contents of a physical register to get the CFA in order to
+        * begin the virtual unwinding of the stack.
         *
         * NOTE: the return address is guaranteed to be setup by the
         * time this function makes its first function call.
        fde = dwarf_lookup_fde(pc);
        if (!fde) {
                /*
-                * This is our normal exit path - the one that stops the
-                * recursion. There's two reasons why we might exit
-                * here,
+                * This is our normal exit path. There are two reasons
+                * why we might exit here,
                 *
                 *      a) pc has no asscociated DWARF frame info and so
                 *      we don't know how to unwind this frame. This is
  
                } else {
                        /*
-                        * Again, this is the first invocation of this
-                        * recurisve function. We need to physically
-                        * read the contents of a register in order to
-                        * get the Canonical Frame Address for this
+                        * Again, we're starting from the top of the
+                        * stack. We need to physically read
+                        * the contents of a register in order to get
+                        * the Canonical Frame Address for this
                         * function.
                         */
                        frame->cfa = dwarf_read_arch_reg(frame->cfa_register);
        return frame;
  
  bail:
-       dwarf_frame_free_regs(frame);
-       mempool_free(frame, dwarf_frame_pool);
+       dwarf_free_frame(frame);
        return NULL;
  }
  
  static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
-                          unsigned char *end)
+                          unsigned char *end, struct module *mod)
  {
        struct dwarf_cie *cie;
        unsigned long flags;
        cie->initial_instructions = p;
        cie->instructions_end = end;
  
+       cie->mod = mod;
        /* Add to list */
        spin_lock_irqsave(&dwarf_cie_lock, flags);
        list_add_tail(&cie->link, &dwarf_cie_list);
  
  static int dwarf_parse_fde(void *entry, u32 entry_type,
                           void *start, unsigned long len,
-                          unsigned char *end)
+                          unsigned char *end, struct module *mod)
  {
        struct dwarf_fde *fde;
        struct dwarf_cie *cie;
        fde->instructions = p;
        fde->end = end;
  
+       fde->mod = mod;
        /* Add to list. */
        spin_lock_irqsave(&dwarf_fde_lock, flags);
        list_add_tail(&fde->link, &dwarf_fde_list);
@@@ -832,10 -846,8 +845,8 @@@ static void dwarf_unwinder_dump(struct 
        while (1) {
                frame = dwarf_unwind_stack(return_addr, _frame);
  
-               if (_frame) {
-                       dwarf_frame_free_regs(_frame);
-                       mempool_free(_frame, dwarf_frame_pool);
-               }
+               if (_frame)
+                       dwarf_free_frame(_frame);
  
                _frame = frame;
  
                return_addr = frame->return_addr;
                ops->address(data, return_addr, 1);
        }
+       if (frame)
+               dwarf_free_frame(frame);
  }
  
  static struct unwinder dwarf_unwinder = {
@@@ -874,48 -889,28 +888,28 @@@ static void dwarf_unwinder_cleanup(void
  }
  
  /**
-  *    dwarf_unwinder_init - initialise the dwarf unwinder
+  *    dwarf_parse_section - parse DWARF section
+  *    @eh_frame_start: start address of the .eh_frame section
+  *    @eh_frame_end: end address of the .eh_frame section
+  *    @mod: the kernel module containing the .eh_frame section
   *
-  *    Build the data structures describing the .dwarf_frame section to
-  *    make it easier to lookup CIE and FDE entries. Because the
-  *    .eh_frame section is packed as tightly as possible it is not
-  *    easy to lookup the FDE for a given PC, so we build a list of FDE
-  *    and CIE entries that make it easier.
+  *    Parse the information in a .eh_frame section.
   */
- static int __init dwarf_unwinder_init(void)
+ int dwarf_parse_section(char *eh_frame_start, char *eh_frame_end,
+                       struct module *mod)
  {
        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;
-       INIT_LIST_HEAD(&dwarf_cie_list);
-       INIT_LIST_HEAD(&dwarf_fde_list);
  
        c_entries = 0;
        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);
+       entry = eh_frame_start;
  
-       dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
-                                        mempool_alloc_slab,
-                                        mempool_free_slab,
-                                        dwarf_reg_cachep);
-       while ((char *)entry < __stop_eh_frame) {
+       while ((char *)entry < eh_frame_end) {
                p = entry;
  
                count = dwarf_entry_len(p, &len);
                         * entry and move to the next one because 'len'
                         * tells us where our next entry is.
                         */
+                       err = -EINVAL;
                        goto out;
                } else
                        p += count;
                p += 4;
  
                if (entry_type == DW_EH_FRAME_CIE) {
-                       err = dwarf_parse_cie(entry, p, len, end);
+                       err = dwarf_parse_cie(entry, p, len, end, mod);
                        if (err < 0)
                                goto out;
                        else
                                c_entries++;
                } else {
-                       err = dwarf_parse_fde(entry, entry_type, p, len, end);
+                       err = dwarf_parse_fde(entry, entry_type, p, len,
+                                             end, mod);
                        if (err < 0)
                                goto out;
                        else
        printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n",
               c_entries, f_entries);
  
 -                      sizeof(struct dwarf_frame), 0, SLAB_PANIC, NULL);
+       return 0;
+ out:
+       return err;
+ }
+ /**
+  *    dwarf_module_unload - remove FDE/CIEs associated with @mod
+  *    @mod: the module that is being unloaded
+  *
+  *    Remove any FDEs and CIEs from the global lists that came from
+  *    @mod's .eh_frame section because @mod is being unloaded.
+  */
+ void dwarf_module_unload(struct module *mod)
+ {
+       struct dwarf_fde *fde;
+       struct dwarf_cie *cie;
+       unsigned long flags;
+       spin_lock_irqsave(&dwarf_cie_lock, flags);
+ again_cie:
+       list_for_each_entry(cie, &dwarf_cie_list, link) {
+               if (cie->mod == mod)
+                       break;
+       }
+       if (&cie->link != &dwarf_cie_list) {
+               list_del(&cie->link);
+               kfree(cie);
+               goto again_cie;
+       }
+       spin_unlock_irqrestore(&dwarf_cie_lock, flags);
+       spin_lock_irqsave(&dwarf_fde_lock, flags);
+ again_fde:
+       list_for_each_entry(fde, &dwarf_fde_list, link) {
+               if (fde->mod == mod)
+                       break;
+       }
+       if (&fde->link != &dwarf_fde_list) {
+               list_del(&fde->link);
+               kfree(fde);
+               goto again_fde;
+       }
+       spin_unlock_irqrestore(&dwarf_fde_lock, flags);
+ }
+ /**
+  *    dwarf_unwinder_init - initialise the dwarf unwinder
+  *
+  *    Build the data structures describing the .dwarf_frame section to
+  *    make it easier to lookup CIE and FDE entries. Because the
+  *    .eh_frame section is packed as tightly as possible it is not
+  *    easy to lookup the FDE for a given PC, so we build a list of FDE
+  *    and CIE entries that make it easier.
+  */
+ static int __init dwarf_unwinder_init(void)
+ {
+       int err;
+       INIT_LIST_HEAD(&dwarf_cie_list);
+       INIT_LIST_HEAD(&dwarf_fde_list);
+       dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
 -                      sizeof(struct dwarf_reg), 0, SLAB_PANIC, NULL);
++                      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);
+       err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
+       if (err)
+               goto out;
        err = unwinder_register(&dwarf_unwinder);
        if (err)
                goto out;