fpbinject 1.6.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. fpbinject-1.6.8/LICENSE +21 -0
  2. fpbinject-1.6.8/PKG-INFO +255 -0
  3. fpbinject-1.6.8/README.md +220 -0
  4. fpbinject-1.6.8/Tools/WebServer/__init__.py +10 -0
  5. fpbinject-1.6.8/Tools/WebServer/__main__.py +9 -0
  6. fpbinject-1.6.8/Tools/WebServer/app/__init__.py +41 -0
  7. fpbinject-1.6.8/Tools/WebServer/app/auto_ban.py +365 -0
  8. fpbinject-1.6.8/Tools/WebServer/app/middleware.py +155 -0
  9. fpbinject-1.6.8/Tools/WebServer/app/routes/__init__.py +42 -0
  10. fpbinject-1.6.8/Tools/WebServer/app/routes/connection.py +402 -0
  11. fpbinject-1.6.8/Tools/WebServer/app/routes/files.py +280 -0
  12. fpbinject-1.6.8/Tools/WebServer/app/routes/fpb.py +758 -0
  13. fpbinject-1.6.8/Tools/WebServer/app/routes/logs.py +308 -0
  14. fpbinject-1.6.8/Tools/WebServer/app/routes/patch.py +233 -0
  15. fpbinject-1.6.8/Tools/WebServer/app/routes/symbols.py +1521 -0
  16. fpbinject-1.6.8/Tools/WebServer/app/routes/transfer.py +830 -0
  17. fpbinject-1.6.8/Tools/WebServer/app/routes/watch.py +174 -0
  18. fpbinject-1.6.8/Tools/WebServer/app/routes/watch_expr.py +237 -0
  19. fpbinject-1.6.8/Tools/WebServer/app/utils/__init__.py +0 -0
  20. fpbinject-1.6.8/Tools/WebServer/app/utils/sse.py +80 -0
  21. fpbinject-1.6.8/Tools/WebServer/cli/__init__.py +12 -0
  22. fpbinject-1.6.8/Tools/WebServer/cli/connection_plan.py +67 -0
  23. fpbinject-1.6.8/Tools/WebServer/cli/discover.py +295 -0
  24. fpbinject-1.6.8/Tools/WebServer/cli/fpb_cli.py +2242 -0
  25. fpbinject-1.6.8/Tools/WebServer/cli/handle_cache.py +128 -0
  26. fpbinject-1.6.8/Tools/WebServer/cli/server_proxy.py +553 -0
  27. fpbinject-1.6.8/Tools/WebServer/core/__init__.py +2 -0
  28. fpbinject-1.6.8/Tools/WebServer/core/compile_commands.py +426 -0
  29. fpbinject-1.6.8/Tools/WebServer/core/compiler.py +738 -0
  30. fpbinject-1.6.8/Tools/WebServer/core/config_schema.py +500 -0
  31. fpbinject-1.6.8/Tools/WebServer/core/elf_utils.py +779 -0
  32. fpbinject-1.6.8/Tools/WebServer/core/file_transfer.py +699 -0
  33. fpbinject-1.6.8/Tools/WebServer/core/gdb_bridge.py +469 -0
  34. fpbinject-1.6.8/Tools/WebServer/core/gdb_json_print.py +115 -0
  35. fpbinject-1.6.8/Tools/WebServer/core/gdb_manager.py +359 -0
  36. fpbinject-1.6.8/Tools/WebServer/core/gdb_session.py +1281 -0
  37. fpbinject-1.6.8/Tools/WebServer/core/patch_generator.py +493 -0
  38. fpbinject-1.6.8/Tools/WebServer/core/serial_protocol.py +1182 -0
  39. fpbinject-1.6.8/Tools/WebServer/core/state.py +390 -0
  40. fpbinject-1.6.8/Tools/WebServer/core/watch_evaluator.py +290 -0
  41. fpbinject-1.6.8/Tools/WebServer/fpb_cli.py +42 -0
  42. fpbinject-1.6.8/Tools/WebServer/fpb_inject.py +837 -0
  43. fpbinject-1.6.8/Tools/WebServer/main.py +573 -0
  44. fpbinject-1.6.8/Tools/WebServer/routes.py +59 -0
  45. fpbinject-1.6.8/Tools/WebServer/services/__init__.py +16 -0
  46. fpbinject-1.6.8/Tools/WebServer/services/config_file_watcher.py +0 -0
  47. fpbinject-1.6.8/Tools/WebServer/services/device_worker.py +306 -0
  48. fpbinject-1.6.8/Tools/WebServer/services/file_watcher.py +314 -0
  49. fpbinject-1.6.8/Tools/WebServer/services/file_watcher_manager.py +504 -0
  50. fpbinject-1.6.8/Tools/WebServer/services/log_recorder.py +124 -0
  51. fpbinject-1.6.8/Tools/WebServer/services/mdns_advertiser.py +224 -0
  52. fpbinject-1.6.8/Tools/WebServer/services/timer.py +129 -0
  53. fpbinject-1.6.8/Tools/WebServer/services/virtual_serial.py +266 -0
  54. fpbinject-1.6.8/Tools/WebServer/static/css/style.css +1192 -0
  55. fpbinject-1.6.8/Tools/WebServer/static/css/tutorial.css +397 -0
  56. fpbinject-1.6.8/Tools/WebServer/static/css/workbench.css +3168 -0
  57. fpbinject-1.6.8/Tools/WebServer/static/js/app.js +65 -0
  58. fpbinject-1.6.8/Tools/WebServer/static/js/core/config-schema.js +727 -0
  59. fpbinject-1.6.8/Tools/WebServer/static/js/core/connection.js +423 -0
  60. fpbinject-1.6.8/Tools/WebServer/static/js/core/i18n.js +175 -0
  61. fpbinject-1.6.8/Tools/WebServer/static/js/core/logs.js +200 -0
  62. fpbinject-1.6.8/Tools/WebServer/static/js/core/slots.js +277 -0
  63. fpbinject-1.6.8/Tools/WebServer/static/js/core/sse.js +81 -0
  64. fpbinject-1.6.8/Tools/WebServer/static/js/core/state.js +225 -0
  65. fpbinject-1.6.8/Tools/WebServer/static/js/core/terminal.js +342 -0
  66. fpbinject-1.6.8/Tools/WebServer/static/js/core/theme.js +90 -0
  67. fpbinject-1.6.8/Tools/WebServer/static/js/core/version.js +13 -0
  68. fpbinject-1.6.8/Tools/WebServer/static/js/features/autoinject.js +549 -0
  69. fpbinject-1.6.8/Tools/WebServer/static/js/features/config.js +602 -0
  70. fpbinject-1.6.8/Tools/WebServer/static/js/features/editor.js +499 -0
  71. fpbinject-1.6.8/Tools/WebServer/static/js/features/elfwatcher.js +163 -0
  72. fpbinject-1.6.8/Tools/WebServer/static/js/features/filebrowser.js +187 -0
  73. fpbinject-1.6.8/Tools/WebServer/static/js/features/fpb.js +554 -0
  74. fpbinject-1.6.8/Tools/WebServer/static/js/features/inline-edit.js +228 -0
  75. fpbinject-1.6.8/Tools/WebServer/static/js/features/patch.js +639 -0
  76. fpbinject-1.6.8/Tools/WebServer/static/js/features/quick-commands.js +1779 -0
  77. fpbinject-1.6.8/Tools/WebServer/static/js/features/symbols.js +1265 -0
  78. fpbinject-1.6.8/Tools/WebServer/static/js/features/transfer.js +2478 -0
  79. fpbinject-1.6.8/Tools/WebServer/static/js/features/tutorial.js +1163 -0
  80. fpbinject-1.6.8/Tools/WebServer/static/js/features/watch.js +815 -0
  81. fpbinject-1.6.8/Tools/WebServer/static/js/lib/beautify.min.js +4915 -0
  82. fpbinject-1.6.8/Tools/WebServer/static/js/lib/i18next.min.js +2632 -0
  83. fpbinject-1.6.8/Tools/WebServer/static/js/locales/en.js +708 -0
  84. fpbinject-1.6.8/Tools/WebServer/static/js/locales/zh-CN.js +665 -0
  85. fpbinject-1.6.8/Tools/WebServer/static/js/locales/zh-TW.js +667 -0
  86. fpbinject-1.6.8/Tools/WebServer/static/js/ui/sash.js +185 -0
  87. fpbinject-1.6.8/Tools/WebServer/static/js/ui/sidebar.js +268 -0
  88. fpbinject-1.6.8/Tools/WebServer/templates/base.html +52 -0
  89. fpbinject-1.6.8/Tools/WebServer/templates/index.html +6 -0
  90. fpbinject-1.6.8/Tools/WebServer/templates/partials/activitybar.html +67 -0
  91. fpbinject-1.6.8/Tools/WebServer/templates/partials/editor.html +70 -0
  92. fpbinject-1.6.8/Tools/WebServer/templates/partials/modals.html +28 -0
  93. fpbinject-1.6.8/Tools/WebServer/templates/partials/scripts.html +110 -0
  94. fpbinject-1.6.8/Tools/WebServer/templates/partials/sidebar.html +248 -0
  95. fpbinject-1.6.8/Tools/WebServer/templates/partials/sidebar_config.html +15 -0
  96. fpbinject-1.6.8/Tools/WebServer/templates/partials/sidebar_device.html +110 -0
  97. fpbinject-1.6.8/Tools/WebServer/templates/partials/sidebar_quick_commands.html +269 -0
  98. fpbinject-1.6.8/Tools/WebServer/templates/partials/sidebar_transfer.html +145 -0
  99. fpbinject-1.6.8/Tools/WebServer/templates/partials/statusbar.html +30 -0
  100. fpbinject-1.6.8/Tools/WebServer/templates/partials/terminal.html +38 -0
  101. fpbinject-1.6.8/Tools/WebServer/templates/partials/titlebar.html +30 -0
  102. fpbinject-1.6.8/Tools/WebServer/templates/partials/tutorial.html +34 -0
  103. fpbinject-1.6.8/Tools/WebServer/utils/__init__.py +13 -0
  104. fpbinject-1.6.8/Tools/WebServer/utils/crc.py +299 -0
  105. fpbinject-1.6.8/Tools/WebServer/utils/helpers.py +108 -0
  106. fpbinject-1.6.8/Tools/WebServer/utils/net.py +146 -0
  107. fpbinject-1.6.8/Tools/WebServer/utils/port_lock.py +169 -0
  108. fpbinject-1.6.8/Tools/WebServer/utils/serial.py +344 -0
  109. fpbinject-1.6.8/Tools/WebServer/utils/toolchain.py +48 -0
  110. fpbinject-1.6.8/Tools/WebServer/version.py +13 -0
  111. fpbinject-1.6.8/fpbinject.egg-info/PKG-INFO +255 -0
  112. fpbinject-1.6.8/fpbinject.egg-info/SOURCES.txt +116 -0
  113. fpbinject-1.6.8/fpbinject.egg-info/dependency_links.txt +1 -0
  114. fpbinject-1.6.8/fpbinject.egg-info/entry_points.txt +3 -0
  115. fpbinject-1.6.8/fpbinject.egg-info/requires.txt +14 -0
  116. fpbinject-1.6.8/fpbinject.egg-info/top_level.txt +1 -0
  117. fpbinject-1.6.8/pyproject.toml +83 -0
  118. fpbinject-1.6.8/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 VIFEX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,255 @@
1
+ Metadata-Version: 2.4
2
+ Name: fpbinject
3
+ Version: 1.6.8
4
+ Summary: Runtime code injection for ARM Cortex-M via the FPB (Flash Patch and Breakpoint) hardware unit
5
+ Author-email: VIFEX <vifextech@foxmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/FASTSHIFT/FPBInject
8
+ Project-URL: Repository, https://github.com/FASTSHIFT/FPBInject
9
+ Keywords: arm,cortex-m,fpb,firmware,code-injection,debugging
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Topic :: Software Development :: Embedded Systems
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Operating System :: MacOS
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: Flask
22
+ Requires-Dist: Flask-Cors
23
+ Requires-Dist: pyserial
24
+ Requires-Dist: pygdbmi
25
+ Requires-Dist: watchdog
26
+ Requires-Dist: tree_sitter
27
+ Requires-Dist: zeroconf>=0.131
28
+ Requires-Dist: platformdirs
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest; extra == "dev"
31
+ Requires-Dist: coverage; extra == "dev"
32
+ Requires-Dist: black; extra == "dev"
33
+ Requires-Dist: flake8; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # FPBInject
37
+
38
+ **English** | [中文](README_zh.md)
39
+
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
+ [![Platform](https://img.shields.io/badge/Platform-STM32F103-blue.svg)](https://www.st.com/en/microcontrollers-microprocessors/stm32f103.html)
42
+ [![Platform](https://img.shields.io/badge/Platform-NuttX-blue.svg)](https://github.com/apache/nuttx)
43
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/FASTSHIFT/FPBInject)
44
+ [![CI](https://github.com/FASTSHIFT/FPBInject/actions/workflows/ci.yml/badge.svg)](https://github.com/FASTSHIFT/FPBInject/actions/workflows/ci.yml)
45
+
46
+ Runtime code injection for ARM Cortex-M. Replace any function on a running MCU through a serial connection — no reflashing, no debugger, no downtime.
47
+
48
+ FPBInject uses the [Flash Patch and Breakpoint (FPB)](https://developer.arm.com/documentation/ddi0337/h/debug/about-the-flash-patch-and-breakpoint-unit--fpb-) hardware unit to intercept function calls and redirect them to your custom code in RAM, while the original Flash stays untouched.
49
+
50
+ ![FPBInject Workbench](Docs/images/webserver-overview.png)
51
+
52
+ ## Traditional vs FPBInject
53
+
54
+ ```mermaid
55
+ gantt
56
+ title Iteration cycle comparison (typical STM32 project)
57
+ dateFormat s
58
+ axisFormat %Ss
59
+
60
+ section Traditional
61
+ Edit code : a1, 0, 5s
62
+ Compile & link : a2, after a1, 15s
63
+ Erase flash : a3, after a2, 3s
64
+ Flash write : a4, after a3, 5s
65
+ MCU reboot : a5, after a4, 2s
66
+ Reproduce issue : a6, after a5, 5s
67
+
68
+ section FPBInject
69
+ Edit code : b1, 0, 5s
70
+ Compile & inject : b2, after b1, 1s
71
+ Reproduce issue : b3, after b2, 5s
72
+ ```
73
+
74
+ The traditional cycle touches flash on every iteration — compile, erase, write, reboot, then finally reproduce the issue. With FPBInject, the MCU never stops: save your patch, it's live in under a second. No pit stop required.
75
+
76
+ ## How It Works
77
+
78
+ ```mermaid
79
+ flowchart LR
80
+ A["caller()<br/>calls foo()"] -->|"FPB intercepts<br/>foo's address"| B["Trampoline<br/>in Flash"]
81
+ B -->|"Jump to RAM"| C["Your Code<br/>in RAM"]
82
+ ```
83
+
84
+ The FPB unit matches the target function's address, redirects execution through a trampoline in Flash, which jumps to your replacement function in RAM. All handled by hardware — zero software overhead on the call path.
85
+
86
+ ## Workbench
87
+
88
+ FPBInject ships with a browser-based workbench for the full workflow: browse symbols, read disassembly, write patches, and inject — all from one interface.
89
+
90
+ ### Symbol Search & Disassembly
91
+
92
+ Search the firmware's symbol table, click a function to view its disassembly or decompiled source.
93
+
94
+ ![Disassembly View](Docs/images/webserver-disasm.png)
95
+
96
+ ### Manual Inject
97
+
98
+ Write your replacement function in C, then hit inject. The workbench compiles, uploads, and patches — typically under a second.
99
+
100
+ ![Inject View](Docs/images/webserver-inject.png)
101
+
102
+ ### Auto Inject
103
+
104
+ Point the workbench at your source directory and enable file watching. Add `/* FPB_INJECT */` before any function you want to patch, then just save the file — the workbench detects the change, recompiles, and re-injects automatically.
105
+
106
+ ![Auto Inject - Editor](Docs/images/editor-auto-inejct.png)
107
+
108
+ ![Auto Inject - Workbench](Docs/images/webserver-auto-inject.png)
109
+
110
+ ## File Transfer (Optional)
111
+
112
+ FPBInject also supports file transfer over serial — browse, upload, and download files on the device's filesystem. Supports drag-and-drop (files and folders), CRC verification, and progress tracking.
113
+
114
+ Filesystem backends: POSIX (NuttX VFS, Linux), FatFS, standard C library (stdio), or custom implementations via the `fl_fs_ops_t` interface.
115
+
116
+ ![File Transfer](Docs/images/file-transfer.png)
117
+
118
+ ## Quick Start
119
+
120
+ ### 1. Build & Flash Firmware
121
+
122
+ ```bash
123
+ git clone https://github.com/FASTSHIFT/FPBInject.git
124
+ cd FPBInject
125
+
126
+ cmake -B build -DAPP_SELECT=3 -DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-gcc.cmake
127
+ cmake --build build
128
+
129
+ st-flash write build/FPBInject.bin 0x08000000
130
+ ```
131
+
132
+ ### 2. Start the Workbench
133
+
134
+ ```bash
135
+ cd Tools/WebServer
136
+ pip install -r ../requirements.txt
137
+ python main.py
138
+ ```
139
+
140
+ Open `http://127.0.0.1:5500` in your browser, connect to the serial port, load your ELF file, and start patching.
141
+
142
+ ### 3. Or Use the CLI
143
+
144
+ All commands output JSON, designed for scripting and AI agent integration.
145
+
146
+ ```bash
147
+ # Search for functions
148
+ python fpb_cli.py search firmware.elf "gpio"
149
+
150
+ # View disassembly
151
+ python fpb_cli.py disasm firmware.elf digitalWrite
152
+
153
+ # Inject a patch
154
+ python fpb_cli.py --port /dev/ttyACM0 --elf firmware.elf \
155
+ --compile-commands build/compile_commands.json \
156
+ inject digitalWrite patch.c
157
+ ```
158
+
159
+ See the [CLI Guide](Docs/CLI.md) for the full command reference.
160
+
161
+ ## Writing Patches
162
+
163
+ Create a C file with the `/* FPB_INJECT */` marker. The function signature must match the original.
164
+
165
+ ```c
166
+ #include <Arduino.h>
167
+
168
+ /* FPB_INJECT */
169
+ __attribute__((section(".fpb.text"), used))
170
+ void digitalWrite(uint8_t pin, uint8_t value) {
171
+ printf("Patched: pin=%d val=%d\n", pin, value);
172
+ value ? digitalWrite_HIGH(pin)
173
+ : digitalWrite_LOW(pin);
174
+ }
175
+ ```
176
+
177
+ > To call the original function from injected code, you need two things: a function pointer pointing directly at the original address (bypassing the FPB redirect), and temporarily disabling the patch around the call. Direct calls by name will still be intercepted by FPB and cause infinite recursion.
178
+ >
179
+ > ```c
180
+ > /* Define a function pointer to the original address (| 1 sets the Thumb bit) */
181
+ > typedef void (*digitalWrite_fn_t)(uint8_t, uint8_t);
182
+ > static digitalWrite_fn_t const ORIG_DIGITALWRITE = (digitalWrite_fn_t)(0x08001234 | 1);
183
+ >
184
+ > /* FPB_INJECT */
185
+ > __attribute__((section(".fpb.text"), used))
186
+ > void digitalWrite(uint8_t pin, uint8_t value) {
187
+ > printf("Patched: pin=%d val=%d\n", pin, value);
188
+ >
189
+ > /* Disable patch -> call original via pointer -> re-enable */
190
+ > fpb_enable_patch(0, false);
191
+ > ORIG_DIGITALWRITE(pin, value);
192
+ > fpb_enable_patch(0, true);
193
+ > }
194
+ > ```
195
+ >
196
+ > The workbench generates this pattern automatically when the original function address is known.
197
+
198
+ ## Supported Hardware
199
+
200
+ | Feature | Spec |
201
+ |---------|------|
202
+ | Architecture | ARMv7-M, ARMv8-M |
203
+ | Tested MCU | STM32F103C8T6 |
204
+ | Patch Slots | 6 (FPB v1) or 8 (FPB v2) |
205
+ | Patch Modes | Trampoline / Direct (ARMv7-M REMAP), DebugMonitor (ARMv8-M BKPT) |
206
+ | RTOS Support | Bare-metal, NuttX |
207
+ | Connection | Serial (USB-to-UART or USB CDC) |
208
+
209
+
210
+ <details>
211
+ <summary>CMake Build Options</summary>
212
+
213
+ | Option | Default | Description |
214
+ |--------|---------|-------------|
215
+ | `APP_SELECT` | 1 | Application selection (3 = func_loader) |
216
+ | `FL_ALLOC_MODE` | STATIC | Memory allocation: STATIC or LIBC |
217
+ | `FPB_NO_DEBUGMON` | OFF | Disable DebugMonitor mode |
218
+
219
+ </details>
220
+
221
+ <details>
222
+ <summary>Project Structure</summary>
223
+
224
+ ```
225
+ FPBInject/
226
+ ├── Source/ # FPB driver, trampoline, DebugMonitor
227
+ ├── App/
228
+ │ ├── func_loader/ # Serial protocol, memory allocator, FPB control
229
+ │ ├── inject/ # Injection helpers
230
+ │ └── tests/ # Firmware unit tests (host-based, with coverage)
231
+ ├── Project/ # Platform HAL (STM32F10x, Arduino API)
232
+ ├── Tools/
233
+ │ └── WebServer/ # Workbench (Flask backend + JS frontend) & CLI
234
+ └── Docs/ # Architecture, CLI reference, WebServer guide
235
+ ```
236
+
237
+ </details>
238
+
239
+ ## Documentation
240
+
241
+ | Document | Description |
242
+ |----------|-------------|
243
+ | [Architecture](Docs/Architecture.md) | FPB internals, patch modes, memory layout, protocol |
244
+ | [CLI Reference](Docs/CLI.md) | All CLI commands with examples and JSON output format |
245
+ | [WebServer Guide](Docs/WebServer.md) | Workbench setup and usage |
246
+
247
+ ## License
248
+
249
+ [MIT](LICENSE)
250
+
251
+ ## References
252
+
253
+ - [ARM Cortex-M3 Technical Reference Manual](https://developer.arm.com/documentation/ddi0337)
254
+ - [ARMv7-M Architecture Reference Manual](https://developer.arm.com/documentation/ddi0403)
255
+ - [STM32F103 Reference Manual](https://www.st.com/resource/en/reference_manual/rm0008.pdf)
@@ -0,0 +1,220 @@
1
+ # FPBInject
2
+
3
+ **English** | [中文](README_zh.md)
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Platform](https://img.shields.io/badge/Platform-STM32F103-blue.svg)](https://www.st.com/en/microcontrollers-microprocessors/stm32f103.html)
7
+ [![Platform](https://img.shields.io/badge/Platform-NuttX-blue.svg)](https://github.com/apache/nuttx)
8
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/FASTSHIFT/FPBInject)
9
+ [![CI](https://github.com/FASTSHIFT/FPBInject/actions/workflows/ci.yml/badge.svg)](https://github.com/FASTSHIFT/FPBInject/actions/workflows/ci.yml)
10
+
11
+ Runtime code injection for ARM Cortex-M. Replace any function on a running MCU through a serial connection — no reflashing, no debugger, no downtime.
12
+
13
+ FPBInject uses the [Flash Patch and Breakpoint (FPB)](https://developer.arm.com/documentation/ddi0337/h/debug/about-the-flash-patch-and-breakpoint-unit--fpb-) hardware unit to intercept function calls and redirect them to your custom code in RAM, while the original Flash stays untouched.
14
+
15
+ ![FPBInject Workbench](Docs/images/webserver-overview.png)
16
+
17
+ ## Traditional vs FPBInject
18
+
19
+ ```mermaid
20
+ gantt
21
+ title Iteration cycle comparison (typical STM32 project)
22
+ dateFormat s
23
+ axisFormat %Ss
24
+
25
+ section Traditional
26
+ Edit code : a1, 0, 5s
27
+ Compile & link : a2, after a1, 15s
28
+ Erase flash : a3, after a2, 3s
29
+ Flash write : a4, after a3, 5s
30
+ MCU reboot : a5, after a4, 2s
31
+ Reproduce issue : a6, after a5, 5s
32
+
33
+ section FPBInject
34
+ Edit code : b1, 0, 5s
35
+ Compile & inject : b2, after b1, 1s
36
+ Reproduce issue : b3, after b2, 5s
37
+ ```
38
+
39
+ The traditional cycle touches flash on every iteration — compile, erase, write, reboot, then finally reproduce the issue. With FPBInject, the MCU never stops: save your patch, it's live in under a second. No pit stop required.
40
+
41
+ ## How It Works
42
+
43
+ ```mermaid
44
+ flowchart LR
45
+ A["caller()<br/>calls foo()"] -->|"FPB intercepts<br/>foo's address"| B["Trampoline<br/>in Flash"]
46
+ B -->|"Jump to RAM"| C["Your Code<br/>in RAM"]
47
+ ```
48
+
49
+ The FPB unit matches the target function's address, redirects execution through a trampoline in Flash, which jumps to your replacement function in RAM. All handled by hardware — zero software overhead on the call path.
50
+
51
+ ## Workbench
52
+
53
+ FPBInject ships with a browser-based workbench for the full workflow: browse symbols, read disassembly, write patches, and inject — all from one interface.
54
+
55
+ ### Symbol Search & Disassembly
56
+
57
+ Search the firmware's symbol table, click a function to view its disassembly or decompiled source.
58
+
59
+ ![Disassembly View](Docs/images/webserver-disasm.png)
60
+
61
+ ### Manual Inject
62
+
63
+ Write your replacement function in C, then hit inject. The workbench compiles, uploads, and patches — typically under a second.
64
+
65
+ ![Inject View](Docs/images/webserver-inject.png)
66
+
67
+ ### Auto Inject
68
+
69
+ Point the workbench at your source directory and enable file watching. Add `/* FPB_INJECT */` before any function you want to patch, then just save the file — the workbench detects the change, recompiles, and re-injects automatically.
70
+
71
+ ![Auto Inject - Editor](Docs/images/editor-auto-inejct.png)
72
+
73
+ ![Auto Inject - Workbench](Docs/images/webserver-auto-inject.png)
74
+
75
+ ## File Transfer (Optional)
76
+
77
+ FPBInject also supports file transfer over serial — browse, upload, and download files on the device's filesystem. Supports drag-and-drop (files and folders), CRC verification, and progress tracking.
78
+
79
+ Filesystem backends: POSIX (NuttX VFS, Linux), FatFS, standard C library (stdio), or custom implementations via the `fl_fs_ops_t` interface.
80
+
81
+ ![File Transfer](Docs/images/file-transfer.png)
82
+
83
+ ## Quick Start
84
+
85
+ ### 1. Build & Flash Firmware
86
+
87
+ ```bash
88
+ git clone https://github.com/FASTSHIFT/FPBInject.git
89
+ cd FPBInject
90
+
91
+ cmake -B build -DAPP_SELECT=3 -DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-gcc.cmake
92
+ cmake --build build
93
+
94
+ st-flash write build/FPBInject.bin 0x08000000
95
+ ```
96
+
97
+ ### 2. Start the Workbench
98
+
99
+ ```bash
100
+ cd Tools/WebServer
101
+ pip install -r ../requirements.txt
102
+ python main.py
103
+ ```
104
+
105
+ Open `http://127.0.0.1:5500` in your browser, connect to the serial port, load your ELF file, and start patching.
106
+
107
+ ### 3. Or Use the CLI
108
+
109
+ All commands output JSON, designed for scripting and AI agent integration.
110
+
111
+ ```bash
112
+ # Search for functions
113
+ python fpb_cli.py search firmware.elf "gpio"
114
+
115
+ # View disassembly
116
+ python fpb_cli.py disasm firmware.elf digitalWrite
117
+
118
+ # Inject a patch
119
+ python fpb_cli.py --port /dev/ttyACM0 --elf firmware.elf \
120
+ --compile-commands build/compile_commands.json \
121
+ inject digitalWrite patch.c
122
+ ```
123
+
124
+ See the [CLI Guide](Docs/CLI.md) for the full command reference.
125
+
126
+ ## Writing Patches
127
+
128
+ Create a C file with the `/* FPB_INJECT */` marker. The function signature must match the original.
129
+
130
+ ```c
131
+ #include <Arduino.h>
132
+
133
+ /* FPB_INJECT */
134
+ __attribute__((section(".fpb.text"), used))
135
+ void digitalWrite(uint8_t pin, uint8_t value) {
136
+ printf("Patched: pin=%d val=%d\n", pin, value);
137
+ value ? digitalWrite_HIGH(pin)
138
+ : digitalWrite_LOW(pin);
139
+ }
140
+ ```
141
+
142
+ > To call the original function from injected code, you need two things: a function pointer pointing directly at the original address (bypassing the FPB redirect), and temporarily disabling the patch around the call. Direct calls by name will still be intercepted by FPB and cause infinite recursion.
143
+ >
144
+ > ```c
145
+ > /* Define a function pointer to the original address (| 1 sets the Thumb bit) */
146
+ > typedef void (*digitalWrite_fn_t)(uint8_t, uint8_t);
147
+ > static digitalWrite_fn_t const ORIG_DIGITALWRITE = (digitalWrite_fn_t)(0x08001234 | 1);
148
+ >
149
+ > /* FPB_INJECT */
150
+ > __attribute__((section(".fpb.text"), used))
151
+ > void digitalWrite(uint8_t pin, uint8_t value) {
152
+ > printf("Patched: pin=%d val=%d\n", pin, value);
153
+ >
154
+ > /* Disable patch -> call original via pointer -> re-enable */
155
+ > fpb_enable_patch(0, false);
156
+ > ORIG_DIGITALWRITE(pin, value);
157
+ > fpb_enable_patch(0, true);
158
+ > }
159
+ > ```
160
+ >
161
+ > The workbench generates this pattern automatically when the original function address is known.
162
+
163
+ ## Supported Hardware
164
+
165
+ | Feature | Spec |
166
+ |---------|------|
167
+ | Architecture | ARMv7-M, ARMv8-M |
168
+ | Tested MCU | STM32F103C8T6 |
169
+ | Patch Slots | 6 (FPB v1) or 8 (FPB v2) |
170
+ | Patch Modes | Trampoline / Direct (ARMv7-M REMAP), DebugMonitor (ARMv8-M BKPT) |
171
+ | RTOS Support | Bare-metal, NuttX |
172
+ | Connection | Serial (USB-to-UART or USB CDC) |
173
+
174
+
175
+ <details>
176
+ <summary>CMake Build Options</summary>
177
+
178
+ | Option | Default | Description |
179
+ |--------|---------|-------------|
180
+ | `APP_SELECT` | 1 | Application selection (3 = func_loader) |
181
+ | `FL_ALLOC_MODE` | STATIC | Memory allocation: STATIC or LIBC |
182
+ | `FPB_NO_DEBUGMON` | OFF | Disable DebugMonitor mode |
183
+
184
+ </details>
185
+
186
+ <details>
187
+ <summary>Project Structure</summary>
188
+
189
+ ```
190
+ FPBInject/
191
+ ├── Source/ # FPB driver, trampoline, DebugMonitor
192
+ ├── App/
193
+ │ ├── func_loader/ # Serial protocol, memory allocator, FPB control
194
+ │ ├── inject/ # Injection helpers
195
+ │ └── tests/ # Firmware unit tests (host-based, with coverage)
196
+ ├── Project/ # Platform HAL (STM32F10x, Arduino API)
197
+ ├── Tools/
198
+ │ └── WebServer/ # Workbench (Flask backend + JS frontend) & CLI
199
+ └── Docs/ # Architecture, CLI reference, WebServer guide
200
+ ```
201
+
202
+ </details>
203
+
204
+ ## Documentation
205
+
206
+ | Document | Description |
207
+ |----------|-------------|
208
+ | [Architecture](Docs/Architecture.md) | FPB internals, patch modes, memory layout, protocol |
209
+ | [CLI Reference](Docs/CLI.md) | All CLI commands with examples and JSON output format |
210
+ | [WebServer Guide](Docs/WebServer.md) | Workbench setup and usage |
211
+
212
+ ## License
213
+
214
+ [MIT](LICENSE)
215
+
216
+ ## References
217
+
218
+ - [ARM Cortex-M3 Technical Reference Manual](https://developer.arm.com/documentation/ddi0337)
219
+ - [ARMv7-M Architecture Reference Manual](https://developer.arm.com/documentation/ddi0403)
220
+ - [STM32F103 Reference Manual](https://www.st.com/resource/en/reference_manual/rm0008.pdf)
@@ -0,0 +1,10 @@
1
+ """FPBInject — runtime code injection for ARM Cortex-M via the FPB unit.
2
+
3
+ This package bundles the WebServer, CLI, and supporting modules. The physical
4
+ layout lives under ``Tools/WebServer/`` and is mapped to the import name
5
+ ``fpbinject`` via setuptools ``package-dir`` (see pyproject.toml).
6
+ """
7
+
8
+ from fpbinject.version import __version__
9
+
10
+ __all__ = ["__version__"]
@@ -0,0 +1,9 @@
1
+ """Enable ``python -m fpbinject`` to launch the WebServer.
2
+
3
+ Equivalent to the ``fpbinject-server`` console script.
4
+ """
5
+
6
+ from fpbinject.main import main
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # MIT License
4
+ # Copyright (c) 2025 - 2026 _VIFEXTech
5
+
6
+ """
7
+ FPBInject WebServer Flask Application Package.
8
+
9
+ This package contains the Flask application factory and route blueprints.
10
+ """
11
+
12
+ import os
13
+
14
+ from flask import Flask
15
+ from flask_cors import CORS
16
+
17
+ # Locate the package root (holds templates/ and static/) via importlib.resources
18
+ # so it resolves correctly whether run from source or an installed wheel.
19
+ try:
20
+ from importlib.resources import files as _res_files
21
+
22
+ WEBSERVER_DIR = str(_res_files("fpbinject"))
23
+ except Exception: # pragma: no cover - fallback for odd layouts
24
+ WEBSERVER_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
25
+
26
+
27
+ def create_app():
28
+ """Create and configure the Flask application."""
29
+ app = Flask(
30
+ "fpbinject",
31
+ template_folder=os.path.join(WEBSERVER_DIR, "templates"),
32
+ static_folder=os.path.join(WEBSERVER_DIR, "static"),
33
+ )
34
+ CORS(app)
35
+
36
+ # Import and register routes
37
+ from fpbinject.routes import register_routes
38
+
39
+ register_routes(app)
40
+
41
+ return app