@@ -23,26 +23,25 @@ FPBInject enables runtime function hooking and code injection on Cortex-M microc
2323
2424## How It Works
2525
26- ```
27- ┌─────────────────────────────────────────────────────────────────────────┐
28- │ FPBInject Injection Flow │
29- ├─────────────────────────────────────────────────────────────────────────┤
30- │ │
31- │ 1. Original Call 2. FPB Intercept 3. Trampoline │
32- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
33- │ │ caller() │ │ FPB Unit │ │ trampoline_0 │ │
34- │ │ calls │────────> │ addr match │───────> │ in Flash │ │
35- │ │ digitalWrite │ │ 0x08008308 │ │ loads target │ │
36- │ └──────────────┘ └──────────────┘ └──────────────┘ │
37- │ │ │
38- │ 4. RAM Code Execution ▼ │
39- │ ┌──────────────────────────────────────────────────────────────────┐ │
40- │ │ inject_digitalWrite() @ 0x20000278 (RAM) │ │
41- │ │ - Custom hook logic executes │ │
42- │ │ - Can call original function or replace entirely │ │
43- │ └──────────────────────────────────────────────────────────────────┘ │
44- │ │
45- └─────────────────────────────────────────────────────────────────────────┘
26+ ``` mermaid
27+ flowchart LR
28+ subgraph step1 ["1. Original Call"]
29+ A["caller()<br/>calls<br/>digitalWrite"]
30+ end
31+
32+ subgraph step2 ["2. FPB Intercept"]
33+ B["FPB Unit<br/>addr match<br/>0x08008308"]
34+ end
35+
36+ subgraph step3 ["3. Trampoline"]
37+ C["trampoline_0<br/>in Flash<br/>loads target"]
38+ end
39+
40+ subgraph step4 ["4. RAM Code Execution"]
41+ D["inject_digitalWrite() @ 0x20000278 (RAM)<br/>• Custom hook logic executes<br/>• Can call original function or replace entirely"]
42+ end
43+
44+ A --> B --> C --> D
4645```
4746
4847### Architecture
@@ -286,34 +285,29 @@ DebugMonitor mode provides a software-based alternative that works on both legac
286285
287286### How DebugMonitor Mode Works
288287
289- ```
290- ┌─────────────────────────────────────────────────────────────────────────┐
291- │ DebugMonitor Redirection Flow │
292- ├─────────────────────────────────────────────────────────────────────────┤
293- │ │
294- │ 1. Function Call 2. FPB Breakpoint 3. DebugMonitor │
295- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
296- │ │ caller() │ │ FPB Unit │ │DebugMon_ │ │
297- │ │ calls │────────> │ BKPT trigger │───────> │Handler() │ │
298- │ │ digitalWrite │ │ @ 0x08008308 │ │ (exception) │ │
299- │ └──────────────┘ └──────────────┘ └──────────────┘ │
300- │ │ │
301- │ 4. Stack Frame Modification ▼ │
302- │ ┌──────────────────────────────────────────────────────────────────┐ │
303- │ │ Exception Stack Frame: │ │
304- │ │ [SP+0] R0 - preserved │ │
305- │ │ [SP+4] R1 - preserved │ │
306- │ │ [SP+8] R2 - preserved │ │
307- │ │ [SP+12] R3 - preserved │ │
308- │ │ [SP+16] R12 - preserved │ │
309- │ │ [SP+20] LR - preserved │ │
310- │ │ [SP+24] PC ◄── MODIFIED to inject_digitalWrite (0x20000278) │ │
311- │ │ [SP+28] xPSR - preserved │ │
312- │ └──────────────────────────────────────────────────────────────────┘ │
313- │ │
314- │ 5. Exception Return → Execution continues at inject_digitalWrite() │
315- │ │
316- └─────────────────────────────────────────────────────────────────────────┘
288+ ``` mermaid
289+ flowchart TB
290+ subgraph step1 ["1. Function Call"]
291+ A["caller()<br/>calls<br/>digitalWrite"]
292+ end
293+
294+ subgraph step2 ["2. FPB Breakpoint"]
295+ B["FPB Unit<br/>BKPT trigger<br/>@ 0x08008308"]
296+ end
297+
298+ subgraph step3 ["3. DebugMonitor"]
299+ C["DebugMon_Handler()<br/>(exception)"]
300+ end
301+
302+ subgraph step4 ["4. Stack Frame Modification"]
303+ D["Exception Stack Frame:<br/>[SP+0] R0 - preserved<br/>[SP+4] R1 - preserved<br/>[SP+8] R2 - preserved<br/>[SP+12] R3 - preserved<br/>[SP+16] R12 - preserved<br/>[SP+20] LR - preserved<br/>[SP+24] PC ◄── MODIFIED to inject_digitalWrite<br/>[SP+28] xPSR - preserved"]
304+ end
305+
306+ subgraph step5 ["5. Exception Return"]
307+ E["Execution continues at<br/>inject_digitalWrite()"]
308+ end
309+
310+ A --> B --> C --> D --> E
317311```
318312
319313### Technical Implementation
@@ -391,36 +385,26 @@ On NuttX RTOS, the DebugMonitor implementation uses NuttX's native `up_debugpoin
391385
392386#### Architecture
393387
394- ```
395- ┌─────────────────────────────────────────────────────────────────────────┐
396- │ NuttX DebugMonitor Implementation │
397- ├─────────────────────────────────────────────────────────────────────────┤
398- │ │
399- │ 1. Initialization │
400- │ ┌──────────────────────────────────────────────────────────────────┐ │
401- │ │ fpb_debugmon_init() │ │
402- │ │ ├── irq_attach(NVIC_IRQ_DBGMONITOR, arm_dbgmonitor, NULL) │ │
403- │ │ │ (Replace vendor's PANIC handler with NuttX's handler) │ │
404- │ │ └── arm_enable_dbgmonitor() │ │
405- │ │ (Initialize FPB/DWT hardware) │ │
406- │ └──────────────────────────────────────────────────────────────────┘ │
407- │ │
408- │ 2. Set Redirect │
409- │ ┌──────────────────────────────────────────────────────────────────┐ │
410- │ │ fpb_debugmon_set_redirect(comp, orig_addr, redirect_addr) │ │
411- │ │ └── up_debugpoint_add(DEBUGPOINT_BREAKPOINT, addr, size, │ │
412- │ │ debugmon_callback, &redirect_info) │ │
413- │ └──────────────────────────────────────────────────────────────────┘ │
414- │ │
415- │ 3. Breakpoint Trigger │
416- │ ┌──────────────────────────────────────────────────────────────────┐ │
417- │ │ CPU hits breakpoint → arm_dbgmonitor() → debugmon_callback() │ │
418- │ │ └── regs = running_regs() ← Get saved register context │ │
419- │ │ └── regs[REG_PC] = redirect_addr ← Modify stacked PC │ │
420- │ │ └── Exception return → Execution at inject function │ │
421- │ └──────────────────────────────────────────────────────────────────┘ │
422- │ │
423- └─────────────────────────────────────────────────────────────────────────┘
388+ ``` mermaid
389+ flowchart TB
390+ subgraph init ["1. Initialization"]
391+ A1["fpb_debugmon_init()"] --> A2["irq_attach(NVIC_IRQ_DBGMONITOR,<br/>arm_dbgmonitor, NULL)<br/><i>Replace vendor's PANIC handler</i>"]
392+ A2 --> A3["arm_enable_dbgmonitor()<br/><i>Initialize FPB/DWT hardware</i>"]
393+ end
394+
395+ subgraph redirect ["2. Set Redirect"]
396+ B1["fpb_debugmon_set_redirect<br/>(comp, orig_addr, redirect_addr)"] --> B2["up_debugpoint_add<br/>(DEBUGPOINT_BREAKPOINT,<br/>addr, size,<br/>debugmon_callback,<br/>&redirect_info)"]
397+ end
398+
399+ subgraph trigger ["3. Breakpoint Trigger"]
400+ C1["CPU hits breakpoint"] --> C2["arm_dbgmonitor()"]
401+ C2 --> C3["debugmon_callback()"]
402+ C3 --> C4["regs = running_regs()<br/><i>Get saved register context</i>"]
403+ C4 --> C5["regs[REG_PC] = redirect_addr<br/><i>Modify stacked PC</i>"]
404+ C5 --> C6["Exception return<br/>→ Execution at inject function"]
405+ end
406+
407+ init --> redirect --> trigger
424408```
425409
426410#### Key NuttX APIs Used
0 commit comments