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