Exception Handler

By mastering this systematic workflow - combining register analysis with stack reconstruction - developers can pinpoint the exact origin of complex faults, transforming opaque system crashes into actionable debugging insights.

HardFault Analysis Guide

Diagnosing a HardFault requires piecing together the system's state at the moment of failure. This guide outlines a structured approach to finding the root cause: interpreting Status Registers to identify the error type, checking Address Registers to locate the specific instruction or data fault, and analyzing the Stack to reconstruct the execution history.

Fault Status Registers (Diagnose Why It Failed)

The Fault Status Registers record the specific events that triggered the exception, serving as the key to diagnosing the root cause. By examining flags in the HFSR and CFSR, you can distinguish between error types - such as memory violations, bus errors, or undefined instructions - to understand exactly why the system failed.

Key Registers Description

  • HFSR (HardFault Status Register): Acts as the top-level indicator. It explains why a fault escalated into a HardFault (e.g., a 'Forced' HardFault due to a disabled handler for a lower-level fault).

  • CFSR (Configurable Fault Status Register): The primary register for diagnosing the specific cause. It is a combined 32-bit register split into three sub-registers:

    • UFSR (Usage Fault Status): Records execution-related faults such as undefined instructions, invalid state transitions, or divide-by-zero errors.

    • BFSR (Bus Fault Status): Records bus interface errors (instruction prefetch, data access). Crucially, it distinguishes between Precise errors (known fault address) and Imprecise errors (write buffering delays).

    • MMFSR (MemManage Fault Status): Records violations related to the Memory Protection Unit (MPU), such as writing to read-only regions or executing from non-executable memory.

Fault Address Registers (Diagnose Where It Failed)

  • MMFAR (MemManage Fault Address Register): Holds the address that caused a MemManage fault. Valid only when the corresponding VALID bit is 1.

  • BFAR (Bus Fault Address Register): Holds the address that caused a Bus fault. Valid only when the corresponding VALID bit is 1.

To pinpoint the exact cause of a crash - such as distinguishing between a stack overflow and a null pointer dereference - you must decode the individual bits in these registers. For a complete and consolidated reference of every bit definition across the HFSR, CFSR, MMFAR, and BFAR, refer to the official ARM application note ARM Keil AN209: Using Cortex-M3/M4/M7 Fault Exceptions.

Core Registers and Scene Reconstruction (Diagnose Execution State)

When a fault occurs, the CPU automatically pushes several core registers onto the stack. By examining these registers, you can reconstruct the execution state at the time of the fault.

Key Debugging Registers and Their Roles

Register

Full Name

Role in Debugging

PC

Program Counter

Crash site. Points to the next instruction to execute; it is used to locate the faulting code.

LR

Link Register

Return address. Helps identify the caller; it is used to build the call chain.

SP

Stack Pointer

Current top of stack. Check for overflow/out-of-range; it is also used to find stacked PC/LR on exception entry.

Note

  • If PC is a reasonable Flash address (e.g., 0x080...) or a RAM address (e.g., 0x20...), the PC value is likely valid.

  • If PC is a strange value (e.g., 0x00000000 or 0xFFFFFFFF), the function pointer may be null, or the stack is corrupted. The PC was restored to a wrong value. This means the program went out of control.

CoreDump Parser Debug Workflow

The DebugAnalyzer tool supports parsing Core Dump data to locate hard faults.

  1. Open the Tool

    Launch DebugAnalyzer, and select Extension Tool ‣ Core Dump Parser from the menu bar to open the configuration page.

    ../../../../_images/CoreDump_setting.png

    Core Dump Parser Setting

  2. Configuration Settings

    Configure the parser settings based on your scenario. Refer to the table below for details:

    Core Dump Parsing Tool Configuration Options

    Option

    Description

    Hard Fault Start Log

    The keyword indicating the start of the exception log in the .log file (e.g., Hard Fault Error or Watchdog Interrupt). See Keywords Table below.

    Hard Fault End Log

    The keyword indicating the end of the exception log in the .log file (e.g., Mem Dump Done).

    Dependency Files (*.htm, *.map)

    Path to the directory containing dependency files (.htm, .map). Ensure these match the running firmware image.

    Dependency Files (*.pickle)

    Path to the directory containing .pickle files.

    Parse Result Directory

    Path where the parsed results will be saved.

    Chip Type

    Select the target IC type (e.g., RTL87x3E or RTL87x3D). Note: Core Dump Parsing is only supported for these types.

    Flash Core Dump

    Check this box if parsing a core dump file read back from flash. If checked, you do not need to fill in Keywords or select a *.log file.

    Select *.bin / *.log Files

    Select the raw binary dump (.bin) and the corresponding log file (.log).

  3. Keywords Reference

    Use the following keywords for the Start/End Log fields based on the fault type:

    Log Parsing Keywords Reference

    Type

    Start Log (Keywords)

    End Log (Keywords)

    Hard Fault

    Hard Fault Error

    RTL87x3E:Mem Dump Done or RTL87x3D:Memory Dump Done

    WDT (Watchdog Timer)

    RTL87x3E:Watchdog Interrupt or RTL87x3D:WDT Interrupt

    RTL87x3E:Mem Dump Done or RTL87x3D:Memory Dump Done

  4. Execute Parsing

    Click the Parse button. The button will be grayed out during processing. Wait for the result window to appear.

    ../../../../_images/CoreDump_parse_result.png

    Core Dump Parser Result

Note

  • Pre-requisite: To use the Core Dump Parser effectively, make sure that the ROM trace file item in the Trace File Path Settings was correctly configured before recording the logs via DebugAnalyzer.

  • Flash Core Dump Mode: If you use the Flash Coredump option, you only need to select the .bin file containing the dump.

Practical Analysis Workflow

  1. Identify the fault type.

    • Read HFSR and CFSR.

    • Decide if it is an MPU fault, a Bus fault, or another type.

  2. Find the fault address.

    • Check MMFAR or BFAR.

    • Use the Valid bit to confirm the address is valid.

  3. Restore the code location.

    • Find the PC value in the stack.

    • Search the PC in the build .map or .disasm file.

    • Locate the source line and the function name.

  4. Trace the callers (build the call chain).

    • Find the LR value in the log bin file.

    • Search this address in the .map file to see who called the faulting function.

    • Move down to the previous caller's LR.

    • Repeat until the call chain is clear.

Simple Case Analysis

../../../../_images/Simple_Hardfault_Log.png

Simple Case Diagram

  • HFSR : Bit 30 = 1

  • CFSR : 0x00000082

  • MMFAR : 0x00000000

Debug Flow:

  1. HFSR Check

    • Bit 30 (FORCED) = 1.

    • Conclusion: This is a forced HardFault. The root cause is in CFSR.

  2. CFSR Check (0x82)

    • Bit 7 (MMARVALID) = 1 → The address in MMFAR is valid.

    • Bit 1 (DACCVIOL) = 1 → Data access violation. The MPU blocked the access.

  3. Address Check

    • MMFAR = 0x00000000.

    • Conclusion: The program tried to read or write address 0x00000000.

  4. Locate the Code

    • Search the PC value in the build .map or .disasm file.

    • Find the exact source line and the faulting function name: hardfault_test.

    ../../../../_images/Simple_Hardfault_Locate_the_Code.png

    Hardfault Locate Code

  5. Trace the Caller

    • Check LR = 0x0031471B.

    • In the .map file, see which function called hardfault_test: main.

    ../../../../_images/Simple_Hardfault_Locate_the_Caller.png

    Hardfault Locate Caller

Complex Case Analysis (Call Chain Reconstruction Example)

../../../../_images/Complex_Hardfault_Log.png

Complex Case Diagram

Determine the Fault Type & Fault Address

HFSR = 0x40000000

CFSR = 0x82 (0x00000082)

MMFAR = 0xDEADBEEF

  • HFSR (HardFault Status Register)

    • Focus: Bit 30 (FORCED)

    • Explanation: If 1, the HardFault was escalated from another fault. You must inspect CFSR.

  • CFSR (Configurable Fault Status Register)

    • Example value: 0x82 (0x00000082)

    • Bit breakdown:

      • Bit 7 (MMARVALID): 1 → The address in MMFAR is valid.

      • Bit 1 (DACCVIOL): 1 → Data Access Violation; the MPU blocked the access.

  • MMFAR (MemManage Fault Address Register)

    • Example: 0xDEADBEEF

    • Explanation: This is the specific memory address that caused the crash. The program tried to read/write this illegal address.

Call Stack Backtracking Principle

When a function is called, the return address (LR) is stored on the stack. To trace back the call chain, you need to analyze how many registers were pushed onto the stack and how much stack space was allocated.

\[\text{Stack offset (words) } = \text{number of registers pushed by PUSH} + \frac{\text{bytes allocated by SUB}}{4}\]
Call Chain Analysis
  • PC : 0x4A7F8

  • LR : 0x869FA9

  1. First-Level Trace (Register-Level)

    • Check PC (0x4A7F8): points to function os_queue_out; the fault occurred while accessing the next pointer.

    • Check LR (0x869FA9): points to the caller audio_session_state_set.

    ../../../../_images/Complex_Hardfault_PC_Code.png

    Complex Hardfault PC Locate

    ../../../../_images/Complex_Hardfault_LR1_Code.png

    Complex Hardfault LR_1 Locate

    ../../../../_images/Complex_Hardfault_Stack_Info1.png

    Complex Hardfault Stack Info 1

  2. Second-Level Trace (Stack-Level - Simple PUSH)

    • Scenario: Find the caller of audio_session_state_set.

    • Behavior: The function PUSHed 13 registers.

    • Calculation: Move down 13 words in the stack.

    • Result: New LR = 0x00869659 → corresponds to audio_track_path_cback.

    ../../../../_images/Complex_Hardfault_Stack_Info2.png

    Complex Hardfault Stack Info 2

    ../../../../_images/Complex_Hardfault_LR2_Code.png

    Complex Hardfault LR_2 Locate

  3. Third-Level Trace (Stack-Level - Complex PUSH + SUB)

    Scenario: Find the caller of audio_track_path_cback.

    Assembly analysis:

    • push {r4–r7, ...} → pushed 4 registers.

    • sub sp, #0x1c → allocated 28 bytes of stack space.

    Math:

    • Offset = 4 + (28 / 4) = 11 words.

    Action: From the current position, move down 11 words in the stack record.

    Result: New LR = 0x0086DAD9 → corresponds to audio_path_destory.

    ../../../../_images/Complex_Hardfault_LR3_Code.png

    Complex Hardfault LR_3 Locate

    ../../../../_images/Complex_Hardfault_Stack_Info3.png

    Complex Hardfault Stack Info 3

    ../../../../_images/Complex_Hardfault_LR4_Code.png

    Complex Hardfault LR_4 Locate

  4. Fourth-Level Trace (Loop Logic)

    Scenario: audio_path_destory only pushed one register.

    Calculation: Move down 1 word.

    Result: Found address 0x00869D3C.

    ../../../../_images/Complex_Hardfault_LR5_Code.png

    Complex Hardfault LR_5 Locate

    ../../../../_images/Complex_Hardfault_Stack_Info4.png

    Complex Hardfault Stack Info 4

    ../../../../_images/Complex_Hardfault_LR6_Code.png

    Complex Hardfault LR_6 Locate

  5. Continue this step-by-step downward analysis of the call chain to identify the root cause of the HardFault.