sh: Handle the DWARF op, DW_CFA_undefined
Matt Fleming [Thu, 20 Aug 2009 18:53:49 +0000 (19:53 +0100)]
Allow a DWARF register to have an undefined value. When applied to the
DWARF return address register this lets lets us label a function as
having no direct caller, e.g. kernel_thread_helper().

Signed-off-by: Matt Fleming <matt@console-pimps.org>

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

index 8b0bcc0..c367ed3 100644 (file)
@@ -297,6 +297,7 @@ struct dwarf_reg {
        unsigned long flags;
 #define DWARF_REG_OFFSET       (1 << 0)
 #define DWARF_VAL_OFFSET       (1 << 1)
+#define DWARF_UNDEFINED                (1 << 2)
 };
 
 /*
@@ -370,6 +371,7 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
 #define CFI_DEF_CFA    .cfi_def_cfa
 #define CFI_REGISTER   .cfi_register
 #define CFI_REL_OFFSET .cfi_rel_offset
+#define CFI_UNDEFINED  .cfi_undefined
 
 #else
 
@@ -383,6 +385,7 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
 #define CFI_DEF_CFA    CFI_IGNORE
 #define CFI_REGISTER   CFI_IGNORE
 #define CFI_REL_OFFSET CFI_IGNORE
+#define CFI_UNDEFINED  CFI_IGNORE
 
 #ifndef __ASSEMBLY__
 static inline void dwarf_unwinder_init(void)
index e6f427c..577302f 100644 (file)
@@ -452,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,
@@ -629,9 +631,16 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
                UNWINDER_BUG();
        }
 
-       /* If we haven't seen the return address reg, we're screwed. */
        reg = dwarf_frame_reg(frame, DWARF_ARCH_RA_REG);
-       UNWINDER_BUG_ON(!reg);
+
+       /*
+        * 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;
+
        UNWINDER_BUG_ON(reg->flags != DWARF_REG_OFFSET);
 
        addr = frame->cfa + reg->addr;