| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- /*
- * Copyright (C) 2012 by Ole Reinhardt (ole.reinhardt@embedded-it.de)
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /* Parts taken from
- * http://www.opensource.apple.com/source/lldb/lldb-159/source/Plugins/Process/Utility/ARMUtils.h?txt
- *
- * University of Illinois/NCSA
- * Open Source License
- *
- * Copyright (c) 2010 Apple Inc.
- * All rights reserved.
- *
- * Developed by:
- *
- * LLDB Team
- *
- * http://lldb.llvm.org/
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal with
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimers.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimers in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the names of the LLDB Team, copyright holders, nor the names of
- * its contributors may be used to endorse or promote products derived from
- * this Software without specific prior written permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
- * SOFTWARE.
- *
- */
- /*!
- * \file arch/cm3/cmsis/cortex_debug.c
- *
- * \verbatim
- * $Id: cortex_debug.c $
- * \endverbatim
- */
- #include <cfg/arch.h>
- #include <sys/types.h>
- #include <sys/thread.h>
- #include <inttypes.h>
- #include <cfg/cortex_debug.h>
- #include <arch/cm3/cortex_debug.h>
- #if defined (MCU_LPC17xx)
- #include <arch/cm3/nxp/lpc17xx_debug_macro.h>
- #elif defined (MCU_STM32)
- #include <arch/cm3/stm/stm32_debug_macro.h>
- #endif
- extern void * _evect; /* End of vector table / start of text segment in FLASH */
- extern void * _etext; /* Start of constants in FLASH */
- #define OPCODE_PUSH_R7 0xB480
- #define OPCODE_PUSH_R7_LR 0xB580
- #define OPCODE_PUSH_MASK 0xFE00
- #define OPCODE_PUSH 0xB400
- #define OPCODE_SUB_SP 0xB080
- #define OPCODE_SUB_SP_MASK 0xFF80
- #define OPCODE_SUB_W_SP 0xF1AD
- #define OPCODE_SUB_W_SP_MASK 0xFBEF
- #define OPCODE_ADD_R7_SP 0xAF00
- #define OPCODE_ADD_R7_SP_MASK 0xFF00
- static char *exception_names[6] = {"Default", "NMI", "Hard Fault", "Mem Fault", "Bus Fault", "Usage Fault"};
- static void DebugPrint(const char *str)
- {
- #ifdef DEBUG_MACRO
- while (*str != 0) {
- if (*str == '\n') DebugPut('\r');
- DebugPut(*str);
- str++;
- }
- #endif
- }
- static void DebugPrintU32Hex(uint32_t val) {
- #ifdef DEBUG_MACRO
- int i;
- for (i = 7; i >= 0; i--) {
- register int nibble = (val >> (4 * i)) & 0x0F;
- DebugPut(nibble < 10 ? '0' + nibble : 'a' + nibble - 10);
- }
- #endif
- }
- static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
- {
- return (val & ~(0xFFFFFFFF << (msbit + 1))) >> lsbit;
- }
- static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
- {
- return bits(val, msbit, msbit);
- }
- static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
- {
- uint32_t m = shift % N;
- return (val >> m) | (val << (N - m));
- }
- // (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
- static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t *carry_out)
- {
- uint32_t imm32; // the expaned result
- const uint32_t i = bit(opcode, 26);
- const uint32_t imm3 = bits(opcode, 14, 12);
- const uint32_t abcdefgh = bits(opcode, 7, 0);
- const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
- if (bits(imm12, 11, 10) == 0)
- {
- switch (bits(imm12, 9, 8)) {
- case 0:
- imm32 = abcdefgh;
- break;
- case 1:
- imm32 = abcdefgh << 16 | abcdefgh;
- break;
- case 2:
- imm32 = abcdefgh << 24 | abcdefgh << 8;
- break;
- case 3:
- imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
- break;
- }
- *carry_out = carry_in;
- }
- else
- {
- const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
- imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
- *carry_out = bit(imm32, 31);
- }
- return imm32;
- }
- static inline uint32_t ThumbExpandImm(uint32_t opcode)
- {
- // 'carry_in' argument to following function call does not affect the imm32 result.
- uint32_t carry_in = 0;
- uint32_t carry_out;
- return ThumbExpandImm_C(opcode, carry_in, &carry_out);
- }
- // imm32 = ZeroExtend(i:imm3:imm8, 32)
- static inline uint32_t ThumbImm12(uint32_t opcode)
- {
- const uint32_t i = bit(opcode, 26);
- const uint32_t imm3 = bits(opcode, 14, 12);
- const uint32_t imm8 = bits(opcode, 7, 0);
- const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
- return imm12;
- }
- static inline uint32_t ThumbImm7(uint32_t opcode)
- {
- return bits(opcode, 6, 0);
- }
- static inline uint32_t ThumbImm8(uint32_t opcode)
- {
- return bits(opcode, 7, 0);
- }
- void CortexRegDump(uint32_t *arg, int exception_type, uint32_t *fp)
- {
- uint32_t stacked_r0;
- uint32_t stacked_r1;
- uint32_t stacked_r2;
- uint32_t stacked_r3;
- uint32_t stacked_r12;
- uint32_t stacked_lr;
- uint32_t stacked_pc;
- uint32_t stacked_psr;
- DebugPrint("\n---------------------------------------------------\n");
- stacked_r0 = ((uint32_t) arg[0]);
- stacked_r1 = ((uint32_t) arg[1]);
- stacked_r2 = ((uint32_t) arg[2]);
- stacked_r3 = ((uint32_t) arg[3]);
- stacked_r12 = ((uint32_t) arg[4]);
- stacked_lr = ((uint32_t) arg[5]);
- stacked_pc = ((uint32_t) arg[6]);
- stacked_psr = ((uint32_t) arg[7]);
- DebugPrint("["); DebugPrint(exception_names[exception_type]); DebugPrint(" handler - all numbers in hex]\n");
- #if defined(SCB_HFSR_FORCED_Msk)
- if (exception_type == 2) {
- /* This is a hard fault handler */
- if ((SCB->HFSR & SCB_HFSR_FORCED_Msk) != 0) {
- DebugPrint("Forced Hard Fault!\n");
- }
- }
- #endif
- DebugPrint("\nR0 = 0x"); DebugPrintU32Hex(stacked_r0);
- DebugPrint("\nR1 = 0x"); DebugPrintU32Hex(stacked_r1);
- DebugPrint("\nR2 = 0x"); DebugPrintU32Hex(stacked_r2);
- DebugPrint("\nR3 = 0x"); DebugPrintU32Hex(stacked_r3);
- DebugPrint("\nR12 = 0x"); DebugPrintU32Hex(stacked_r12);
- DebugPrint("\nLR [R14] = 0x"); DebugPrintU32Hex(stacked_lr);
- DebugPrint("\nPC [R15] = 0x"); DebugPrintU32Hex(stacked_pc);
- DebugPrint("\nPSR = 0x"); DebugPrintU32Hex(stacked_psr);
- DebugPrint("\nBFAR = 0x"); DebugPrintU32Hex(*((volatile unsigned long *)(0xE000ED38)));
- DebugPrint("\nCFSR = 0x"); DebugPrintU32Hex(*((volatile unsigned long *)(0xE000ED28)));
- DebugPrint("\nHFSR = 0x"); DebugPrintU32Hex(*((volatile unsigned long *)(0xE000ED2C)));
- DebugPrint("\nDFSR = 0x"); DebugPrintU32Hex(*((volatile unsigned long *)(0xE000ED30)));
- DebugPrint("\nAFSR = 0x"); DebugPrintU32Hex(*((volatile unsigned long *)(0xE000ED3C)));
- DebugPrint("\nSCB_SHCSR = 0x"); DebugPrintU32Hex(SCB->SHCSR);
- DebugPrint("\n---------------------------------------------------\n");
- #ifdef DEBUG_BACKTRACE
- /* These are experimental enhancements to the exception handler which
- * allow to print out a stack dump and a call trace.
- *
- * For these extensions to work properly, we need frame pointer support.
- * Compiler optimisation must be disabled (-O0)
- *
- * At a minimum, we need the following compiler flags to be enabled:
- *
- * -O0 -mtpcs-frame -mtpcs-leaf-frame -fno-omit-frame-pointer
- *
- * Please consider this code highly experimental. Even if the frame pointer
- * support is enabled in the compiler, gcc does not create correct frame
- * pointers when compiling for CortexM. Instead of base address of the
- * current stack frame, the framepointer register (r7 for CortexM) holds
- * the stack pointer address after allocating stack for local variables etc...
- * This value is quite useless, as we need to know the start of the stack
- * frame, where the lr register value was pushed.
- *
- * Usually the following function entry code is generated (with a few
- * variations):
- *
- * push {r7, lr}
- * sub sp, #32
- * add r7, sp, #0
- *
- * The below code now trys to detect and decode these three instructions.
- * The code searches backwards from the last known PC value.
- * If the above instructions are found, it is assumed, that this is the
- * entry of the current function, and the instructions are decoded
- * to back calculate the real stack pointer value at entry into the function.
- *
- * In the above example:
- *
- * The "frame pointer" is r7. We have to substract 0 and add 32 to the
- * framepointer to get the stack pointer value right after pushing LR to
- * the stack. We then read LR from the stack memory to get the address
- * where the current functions has been called from. Further more we read
- * R7 from the stack to also get the next "frame pointer".
- * The above steps are repeated until we reached the base of the current
- * stack or got an invalid stack pointer value.
- *
- * The backtrace only works for functions that are compiled with exactly
- * the above compiler options. E.g. it will not work for included
- * binary only libraries like newlib.
- */
- uint32_t offs;
- uint32_t *sp;
- uint16_t *pc;
- uint16_t *lr;
- uint16_t *saved_pc;
-
- DebugPrint("\nStack:\n\n");
- /* Print out stack, beginning with the current frame pointer. Frame pointer
- * (r7) is only available, if compiled with above compiler options.
- */
- sp = fp;
- for (offs = 0; offs < 128; offs += 4) {
- DebugPrintU32Hex((uint32_t)sp); DebugPrint(": ");
- DebugPrintU32Hex(*(sp++)); DebugPut(' '); DebugPrintU32Hex(*(sp++)); DebugPut(' '); DebugPrintU32Hex(*(sp++)); DebugPut(' '); DebugPrintU32Hex(*(sp++)); DebugPut(' ');
- DebugPrint("\n");
- }
-
- DebugPrint("\n---------------------------------------------------\n");
- /* We try to trace back the last function calls and print out a stack trace */
- DebugPrint("\nCall Trace:\n\n");
- DebugPrint("\nInitial fp: 0x");DebugPrintU32Hex((uint32_t) fp); DebugPrint("\n\n");
- pc = (uint16_t*)(stacked_pc & 0xFFFFFFFE);
- if (fp <= (uint32_t*)runningThread->td_memory) {
- DebugPrint("\nInvalid frame pointer! Out of thread stack bounds:\n\n");
- DebugPrint("PC: ");DebugPrintU32Hex((uint32_t)pc); DebugPrint("\n");
- DebugPrint("FP: ");DebugPrintU32Hex((uint32_t)fp); DebugPrint("\n");
- DebugPrint("Thread stack base: ");DebugPrintU32Hex((uint32_t)runningThread->td_memory); DebugPrint("\n");
- } else {
- DebugPrint("\n Addr: Function: Offset: Frame pointer:\n");
- lr = pc;
- int count = 0;
- while (((uint32_t)pc > (stacked_pc & 0xF8000000) + 2) &&
- ((uint32_t)fp > 0) && (fp > (uint32_t*)runningThread->td_memory)) {
- /* Probe for the instruction entry "signature": push {r7, lr, more regs}; sub sp, #x; add r7, sp, #y; */
- if ((((*pc & OPCODE_PUSH_MASK) == OPCODE_PUSH) && ((*(pc + 1) & OPCODE_SUB_SP_MASK) == OPCODE_SUB_SP) && ((*(pc + 2) & OPCODE_ADD_R7_SP_MASK) == OPCODE_ADD_R7_SP)) ||
- (((*pc & OPCODE_PUSH_MASK) == OPCODE_PUSH) && ((*(pc + 1) & OPCODE_SUB_W_SP_MASK) == OPCODE_SUB_W_SP) && ((*(pc + 3) & OPCODE_ADD_R7_SP_MASK) == OPCODE_ADD_R7_SP)) ||
- (((*pc & OPCODE_PUSH_MASK) == OPCODE_PUSH) && ((*(pc + 1) & OPCODE_ADD_R7_SP_MASK) == OPCODE_ADD_R7_SP))) {
- /* Found the function entry. Minimum R7 is pushed. LR only on node functions */
- DebugPrint("\n 0x"); DebugPrintU32Hex((uint32_t) lr); DebugPrint(" = [0x"); DebugPrintU32Hex((uint32_t) pc); DebugPrint("] + 0x"); DebugPrintU32Hex((uint32_t) (lr - pc) * 2); DebugPrint(": ");
- /* Increment pc to read next opcode. Very likely 'sub pc, #x' */
- saved_pc = pc;
- pc ++;
- if ((*pc & OPCODE_SUB_SP_MASK) == OPCODE_SUB_SP) {
- /* sub pc, #x */
- DebugPrint(" Sub: 0x"); DebugPrintU32Hex(ThumbImm7(*pc)); DebugPrint("\n");
-
- fp = fp + ThumbImm7(*pc); /* Add value which was substracted and function entry + 1, for the LR and the FP address (R7) itself */
- pc ++;
- } else
- if ((*pc & OPCODE_SUB_W_SP_MASK) == OPCODE_SUB_SP) {
- /* sub.w sp, sp, #x */
- fp = fp + ThumbExpandImm((uint32_t)*pc << 16 | (uint32_t)*(pc + 1)) / sizeof(uint32_t);
- pc += 2;
- }
- if ((*pc & OPCODE_ADD_R7_SP_MASK) == OPCODE_ADD_R7_SP) {
- /* add r7, sp, #x */
- fp = fp - ThumbImm8(*pc);
- DebugPrint(" fp: 0x");
- DebugPrintU32Hex((uint32_t) fp);
- // if (*(pc - 2) == OPCODE_PUSH_R7) {
- if (*(saved_pc) == OPCODE_PUSH_R7) {
- /* Set pc to stacked_lr value, which is the calling function */
- pc = (uint16_t*)(stacked_lr & 0xFFFFFFFE);
- } else {
- pc = (uint16_t*)((*(fp + 1)) & 0xFFFFFFFE);
- }
- lr = pc;
- fp = (uint32_t*)*fp;
-
- count ++;
- if (((uint32_t)fp == 0) || (fp < (uint32_t*)runningThread->td_memory)) {
- DebugPrint("\n\nInvalid next frame pointer! Out of thread stack bounds:");
- DebugPrint("\nfp: 0x"); DebugPrintU32Hex((uint32_t) fp);
- DebugPrint("\npc: 0x"); DebugPrintU32Hex((uint32_t) pc);
- DebugPrint("\n");
- }
- }
- }
- pc --;
- }
- }
- #endif
- DebugPrint("\n\nHalted...");
-
- __asm("BKPT #0\n") ; // Break into the debugger
- while(1);
- }
|