platform: Store callee saved register in exception information

Store the callee saved registers in the exception information logging.
We store the current exception frame, which has the registers of the
caller saved registers when the exception occurs, but the callee saved
register information is lost during the exception handling.
This provides us with an incomplete picture of the state at the time
the exception occurred.

Change-Id: I3d15f9eccf1aa8c2c1b99e75e38229ab82420f36
Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
diff --git a/platform/ext/common/exception_info.c b/platform/ext/common/exception_info.c
index 11180be..c9cdc3b 100644
--- a/platform/ext/common/exception_info.c
+++ b/platform/ext/common/exception_info.c
@@ -117,6 +117,16 @@
     SPMLOG_DBGMSGVAL("        PC:   ", ctx->EXC_FRAME_COPY[6]);
     SPMLOG_DBGMSGVAL("        xPSR: ", ctx->EXC_FRAME_COPY[7]);
 
+    SPMLOG_DBGMSG("    Callee saved register state:");
+    SPMLOG_DBGMSGVAL("        R4:   ", ctx->CALLEE_SAVED_COPY[0]);
+    SPMLOG_DBGMSGVAL("        R5:   ", ctx->CALLEE_SAVED_COPY[1]);
+    SPMLOG_DBGMSGVAL("        R6:   ", ctx->CALLEE_SAVED_COPY[2]);
+    SPMLOG_DBGMSGVAL("        R7:   ", ctx->CALLEE_SAVED_COPY[3]);
+    SPMLOG_DBGMSGVAL("        R8:   ", ctx->CALLEE_SAVED_COPY[4]);
+    SPMLOG_DBGMSGVAL("        R9:   ", ctx->CALLEE_SAVED_COPY[5]);
+    SPMLOG_DBGMSGVAL("        R10:  ", ctx->CALLEE_SAVED_COPY[6]);
+    SPMLOG_DBGMSGVAL("        R11:  ", ctx->CALLEE_SAVED_COPY[7]);
+
 #ifdef FAULT_STATUS_PRESENT
     SPMLOG_DBGMSGVAL("    CFSR:  ", ctx->CFSR);
     SPMLOG_DBGMSGVAL("    BFSR:  ",
@@ -196,7 +206,8 @@
     memcpy(ctx, &exception_info, sizeof(exception_info));
 }
 
-void store_and_dump_context(uint32_t LR_in, uint32_t MSP_in, uint32_t PSP_in)
+void store_and_dump_context(uint32_t MSP_in, uint32_t PSP_in, uint32_t LR_in,
+                            uint32_t *callee_saved)
 {
     struct exception_info_t *ctx = &exception_info;
 
@@ -208,6 +219,10 @@
     ctx->EXC_FRAME = get_exception_frame(ctx->EXC_RETURN, ctx->MSP, ctx->PSP);
     memcpy(ctx->EXC_FRAME_COPY, ctx->EXC_FRAME, sizeof(ctx->EXC_FRAME_COPY));
 
+    if (callee_saved) {
+        memcpy(ctx->CALLEE_SAVED_COPY, callee_saved, sizeof(ctx->CALLEE_SAVED_COPY));
+    }
+
 #ifdef FAULT_STATUS_PRESENT
     ctx->CFSR = SCB->CFSR;
     ctx->HFSR = SCB->HFSR;
diff --git a/platform/include/exception_info.h b/platform/include/exception_info.h
index e2d115f..9502008 100644
--- a/platform/include/exception_info.h
+++ b/platform/include/exception_info.h
@@ -40,6 +40,7 @@
     uint32_t PSP;               /* (Secure) PSP. */
     uint32_t *EXC_FRAME;        /* Exception frame on stack. */
     uint32_t EXC_FRAME_COPY[8]; /* Copy of the basic exception frame. */
+    uint32_t CALLEE_SAVED_COPY[8]; /* Copy of the callee saved registers. */
     uint32_t xPSR;              /* Program Status Registers. */
 
 #ifdef FAULT_STATUS_PRESENT
@@ -68,20 +69,54 @@
 /* Store context for an exception, then print the info.
  * Call EXCEPTION_INFO() instead of calling this directly.
  */
-void store_and_dump_context(uint32_t LR_in, uint32_t MSP_in, uint32_t PSP_in);
+void store_and_dump_context(uint32_t MSP_in, uint32_t PSP_in, uint32_t LR_in,
+                            uint32_t *callee_saved);
 
 /* IAR Specific */
 #if defined(__ICCARM__)
 #pragma required = store_and_dump_context
 #endif
 
-#define EXCEPTION_INFO()                                \
-    __ASM volatile(                                     \
-        "MOV     r0, lr\n"                              \
-        "MRS     r1, MSP\n"                             \
-        "MRS     r2, PSP\n"                             \
-        "BL      store_and_dump_context\n"              \
+#if defined(__ARM_ARCH_8M_BASE__) || defined(__ARCM_ARCH_V6_M__)
+#define EXCEPTION_INFO()                   \
+    __ASM volatile(                        \
+        "MRS    R0, MSP\n"                 \
+        "MRS    R1, PSP\n"                 \
+        "MOV    R2, R11\n"                 \
+        "MOV    R3, R10\n"                 \
+        "PUSH   {R2, R3}\n"                \
+        "MOV    R2, R9\n"                  \
+        "MOV    R3, R8\n"                  \
+        "PUSH   {R2, R3}\n"                \
+        "PUSH   {R4-R7}\n"                 \
+        "MOV    R3, SP\n"                  \
+        "MOV    R2, LR\n"                  \
+        "BL     store_and_dump_context\n"  \
+        "ADD    SP, #32\n"                 \
     )
+#elif defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \
+      defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+#define EXCEPTION_INFO()                   \
+    __ASM volatile(                        \
+        "MRS    R0, MSP\n"                 \
+        "MRS    R1, PSP\n"                 \
+        "PUSH   {R4-R11}\n"                \
+        "MOV    R3, SP\n"                  \
+        "MOV    R2, LR\n"                  \
+        "BL     store_and_dump_context\n"  \
+        "ADD    SP, #32\n"                 \
+    )
+#else
+/* Unhandled arch, call store_and_dump_context with callee_saved = NULL */
+#define EXCEPTION_INFO()                   \
+    __ASM volatile(                        \
+        "MRS    R0, MSP\n"                 \
+        "MRS    R1, PSP\n"                 \
+        "MOV    R2, LR\n"                  \
+        "MOV    R3, #0\n"                  \
+        "BL     store_and_dump_context\n"  \
+    )
+#endif
 
 #else /* TFM_EXCEPTION_INFO_DUMP */
 #define EXCEPTION_INFO()