| Robin Getz | 2a12c46 | 2010-03-11 16:24:18 +0000 | [diff] [blame] | 1 | /* Provide basic stack dumping functions | 
|  | 2 | * | 
|  | 3 | * Copyright 2004-2009 Analog Devices Inc. | 
|  | 4 | * | 
|  | 5 | * Licensed under the GPL-2 or later | 
|  | 6 | */ | 
|  | 7 |  | 
|  | 8 | #include <linux/kernel.h> | 
|  | 9 | #include <linux/thread_info.h> | 
|  | 10 | #include <linux/mm.h> | 
|  | 11 | #include <linux/uaccess.h> | 
|  | 12 | #include <linux/module.h> | 
|  | 13 | #include <asm/trace.h> | 
|  | 14 |  | 
|  | 15 | /* | 
|  | 16 | * Checks to see if the address pointed to is either a | 
|  | 17 | * 16-bit CALL instruction, or a 32-bit CALL instruction | 
|  | 18 | */ | 
|  | 19 | static bool is_bfin_call(unsigned short *addr) | 
|  | 20 | { | 
| Robin Getz | 9a95e2f | 2010-03-15 17:42:07 +0000 | [diff] [blame] | 21 | unsigned int opcode; | 
| Robin Getz | 2a12c46 | 2010-03-11 16:24:18 +0000 | [diff] [blame] | 22 |  | 
| Robin Getz | 9a95e2f | 2010-03-15 17:42:07 +0000 | [diff] [blame] | 23 | if (!get_instruction(&opcode, addr)) | 
| Robin Getz | 2a12c46 | 2010-03-11 16:24:18 +0000 | [diff] [blame] | 24 | return false; | 
|  | 25 |  | 
|  | 26 | if ((opcode >= 0x0060 && opcode <= 0x0067) || | 
| Robin Getz | 9a95e2f | 2010-03-15 17:42:07 +0000 | [diff] [blame] | 27 | (opcode >= 0x0070 && opcode <= 0x0077) || | 
|  | 28 | (opcode >= 0xE3000000 && opcode <= 0xE3FFFFFF)) | 
| Robin Getz | 2a12c46 | 2010-03-11 16:24:18 +0000 | [diff] [blame] | 29 | return true; | 
|  | 30 |  | 
|  | 31 | return false; | 
|  | 32 |  | 
|  | 33 | } | 
|  | 34 |  | 
|  | 35 | void show_stack(struct task_struct *task, unsigned long *stack) | 
|  | 36 | { | 
|  | 37 | #ifdef CONFIG_PRINTK | 
|  | 38 | unsigned int *addr, *endstack, *fp = 0, *frame; | 
|  | 39 | unsigned short *ins_addr; | 
|  | 40 | char buf[150]; | 
|  | 41 | unsigned int i, j, ret_addr, frame_no = 0; | 
|  | 42 |  | 
|  | 43 | /* | 
|  | 44 | * If we have been passed a specific stack, use that one otherwise | 
|  | 45 | *    if we have been passed a task structure, use that, otherwise | 
|  | 46 | *    use the stack of where the variable "stack" exists | 
|  | 47 | */ | 
|  | 48 |  | 
|  | 49 | if (stack == NULL) { | 
|  | 50 | if (task) { | 
|  | 51 | /* We know this is a kernel stack, so this is the start/end */ | 
|  | 52 | stack = (unsigned long *)task->thread.ksp; | 
|  | 53 | endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE); | 
|  | 54 | } else { | 
|  | 55 | /* print out the existing stack info */ | 
|  | 56 | stack = (unsigned long *)&stack; | 
|  | 57 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | 
|  | 58 | } | 
|  | 59 | } else | 
|  | 60 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | 
|  | 61 |  | 
|  | 62 | printk(KERN_NOTICE "Stack info:\n"); | 
|  | 63 | decode_address(buf, (unsigned int)stack); | 
|  | 64 | printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); | 
|  | 65 |  | 
|  | 66 | if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) { | 
|  | 67 | printk(KERN_NOTICE "Invalid stack pointer\n"); | 
|  | 68 | return; | 
|  | 69 | } | 
|  | 70 |  | 
|  | 71 | /* First thing is to look for a frame pointer */ | 
|  | 72 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) { | 
|  | 73 | if (*addr & 0x1) | 
|  | 74 | continue; | 
|  | 75 | ins_addr = (unsigned short *)*addr; | 
|  | 76 | ins_addr--; | 
|  | 77 | if (is_bfin_call(ins_addr)) | 
|  | 78 | fp = addr - 1; | 
|  | 79 |  | 
|  | 80 | if (fp) { | 
|  | 81 | /* Let's check to see if it is a frame pointer */ | 
|  | 82 | while (fp >= (addr - 1) && fp < endstack | 
|  | 83 | && fp && ((unsigned int) fp & 0x3) == 0) | 
|  | 84 | fp = (unsigned int *)*fp; | 
|  | 85 | if (fp == 0 || fp == endstack) { | 
|  | 86 | fp = addr - 1; | 
|  | 87 | break; | 
|  | 88 | } | 
|  | 89 | fp = 0; | 
|  | 90 | } | 
|  | 91 | } | 
|  | 92 | if (fp) { | 
|  | 93 | frame = fp; | 
|  | 94 | printk(KERN_NOTICE " FP: (0x%p)\n", fp); | 
|  | 95 | } else | 
|  | 96 | frame = 0; | 
|  | 97 |  | 
|  | 98 | /* | 
|  | 99 | * Now that we think we know where things are, we | 
|  | 100 | * walk the stack again, this time printing things out | 
|  | 101 | * incase there is no frame pointer, we still look for | 
|  | 102 | * valid return addresses | 
|  | 103 | */ | 
|  | 104 |  | 
|  | 105 | /* First time print out data, next time, print out symbols */ | 
|  | 106 | for (j = 0; j <= 1; j++) { | 
|  | 107 | if (j) | 
|  | 108 | printk(KERN_NOTICE "Return addresses in stack:\n"); | 
|  | 109 | else | 
|  | 110 | printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack); | 
|  | 111 |  | 
|  | 112 | fp = frame; | 
|  | 113 | frame_no = 0; | 
|  | 114 |  | 
|  | 115 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0; | 
|  | 116 | addr < endstack; addr++, i++) { | 
|  | 117 |  | 
|  | 118 | ret_addr = 0; | 
|  | 119 | if (!j && i % 8 == 0) | 
|  | 120 | printk(KERN_NOTICE "%p:", addr); | 
|  | 121 |  | 
|  | 122 | /* if it is an odd address, or zero, just skip it */ | 
|  | 123 | if (*addr & 0x1 || !*addr) | 
|  | 124 | goto print; | 
|  | 125 |  | 
|  | 126 | ins_addr = (unsigned short *)*addr; | 
|  | 127 |  | 
|  | 128 | /* Go back one instruction, and see if it is a CALL */ | 
|  | 129 | ins_addr--; | 
|  | 130 | ret_addr = is_bfin_call(ins_addr); | 
|  | 131 | print: | 
|  | 132 | if (!j && stack == (unsigned long *)addr) | 
|  | 133 | printk("[%08x]", *addr); | 
|  | 134 | else if (ret_addr) | 
|  | 135 | if (j) { | 
|  | 136 | decode_address(buf, (unsigned int)*addr); | 
|  | 137 | if (frame == addr) { | 
|  | 138 | printk(KERN_NOTICE "   frame %2i : %s\n", frame_no, buf); | 
|  | 139 | continue; | 
|  | 140 | } | 
|  | 141 | printk(KERN_NOTICE "    address : %s\n", buf); | 
|  | 142 | } else | 
|  | 143 | printk("<%08x>", *addr); | 
|  | 144 | else if (fp == addr) { | 
|  | 145 | if (j) | 
|  | 146 | frame = addr+1; | 
|  | 147 | else | 
|  | 148 | printk("(%08x)", *addr); | 
|  | 149 |  | 
|  | 150 | fp = (unsigned int *)*addr; | 
|  | 151 | frame_no++; | 
|  | 152 |  | 
|  | 153 | } else if (!j) | 
|  | 154 | printk(" %08x ", *addr); | 
|  | 155 | } | 
|  | 156 | if (!j) | 
|  | 157 | printk("\n"); | 
|  | 158 | } | 
|  | 159 | #endif | 
|  | 160 | } | 
|  | 161 | EXPORT_SYMBOL(show_stack); | 
|  | 162 |  | 
|  | 163 | void dump_stack(void) | 
|  | 164 | { | 
|  | 165 | unsigned long stack; | 
|  | 166 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 
|  | 167 | int tflags; | 
|  | 168 | #endif | 
|  | 169 | trace_buffer_save(tflags); | 
|  | 170 | dump_bfin_trace_buffer(); | 
|  | 171 | show_stack(current, &stack); | 
|  | 172 | trace_buffer_restore(tflags); | 
|  | 173 | } | 
|  | 174 | EXPORT_SYMBOL(dump_stack); |