Repository: probe-rs/probe-rs
Pull request #2318 (2024-03-25 18:58:27)

Update cargo-dist to v0.13, enable ARM builds again

Tiwalun: The build for ARM linux fails because it fails to install libudev, because `apt-get update` is not run before `apt-get install`, see https://github.com/axodotdev/cargo-dist/issues/876.

Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d02d1b2c..c0dbb7a0 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,4 +1,4 @@
-# Copyright 2022-2023, axodotdev
+# Copyright 2022-2024, axodotdev
 # SPDX-License-Identifier: MIT or Apache-2.0
 #
 # CI that:
@@ -6,9 +6,9 @@
 # * checks for a Git Tag that looks like a release
 # * builds artifacts with cargo-dist (archives, installers, hashes)
 # * uploads those artifacts to temporary workflow zip
-# * on success, uploads the artifacts to a Github Release
+# * on success, uploads the artifacts to a GitHub Release
 #
-# Note that the Github Release will be created with a generated
+# Note that the GitHub Release will be created with a generated
 # title/body based on your changelogs.
 
 name: Release
@@ -31,7 +31,7 @@ permissions:
 # packages versioned/released in lockstep).
 #
 # If you push multiple tags at once, separate instances of this workflow will
-# spin up, creating an independent announcement for each one. However Github
+# spin up, creating an independent announcement for each one. However, GitHub
 # will hard limit this to 3 tags per commit, as it will assume more tags is a
 # mistake.
 #
@@ -62,7 +62,7 @@ jobs:
         # we specify bash to get pipefail; it guards against the `curl` command
         # failing. otherwise `sh` won't catch that `curl` returned non-0
         shell: bash
-        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.11.1/cargo-dist-installer.sh | sh"
+        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.13.0/cargo-dist-installer.sh | sh"
       # sure would be cool if github gave us proper conditionals...
       # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible
       # functionality based on whether this is a pull_request, and whether it's from a fork.
@@ -135,7 +135,7 @@ jobs:
         run: |
           # Parse out what we just built and upload it to scratch storage
           echo "paths<<EOF" >> "$GITHUB_OUTPUT"
-          jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT"
+          jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
           echo "EOF" >> "$GITHUB_OUTPUT"
 
           cp dist-manifest.json "$BUILD_MANIFEST_NAME"
@@ -162,7 +162,7 @@ jobs:
           submodules: recursive
       - name: Install cargo-dist
         shell: bash
-        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.11.1/cargo-dist-installer.sh | sh"
+        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.13.0/cargo-dist-installer.sh | sh"
       # Get all the local artifacts for the global tasks to use (for e.g. checksums)
       - name: Fetch local artifacts
         uses: actions/download-artifact@v4
@@ -178,7 +178,7 @@ jobs:
 
           # Parse out what we just built and upload it to scratch storage
           echo "paths<<EOF" >> "$GITHUB_OUTPUT"
-          jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT"
+          jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
           echo "EOF" >> "$GITHUB_OUTPUT"
 
           cp dist-manifest.json "$BUILD_MANIFEST_NAME"
@@ -207,7 +207,7 @@ jobs:
         with:
           submodules: recursive
       - name: Install cargo-dist
-        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.11.1/cargo-dist-installer.sh | sh"
+        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.13.0/cargo-dist-installer.sh | sh"
       # Fetch artifacts from scratch-storage
       - name: Fetch artifacts
         uses: actions/download-artifact@v4
@@ -215,7 +215,7 @@ jobs:
           pattern: artifacts-*
           path: target/distrib/
           merge-multiple: true
-      # This is a harmless no-op for Github Releases, hosting for that happens in "announce"
+      # This is a harmless no-op for GitHub Releases, hosting for that happens in "announce"
       - id: host
         shell: bash
         run: |
@@ -270,7 +270,7 @@ jobs:
           done
           git push
 
-  # Create a Github Release while uploading all files to it
+  # Create a GitHub Release while uploading all files to it
   announce:
     needs:
       - plan
@@ -287,7 +287,7 @@ jobs:
       - uses: actions/checkout@v4
         with:
           submodules: recursive
-      - name: "Download Github Artifacts"
+      - name: "Download GitHub Artifacts"
         uses: actions/download-artifact@v4
         with:
           pattern: artifacts-*
@@ -297,7 +297,7 @@ jobs:
         run: |
           # Remove the granular manifests
           rm -f artifacts/*-dist-manifest.json
-      - name: Create Github Release
+      - name: Create GitHub Release
         uses: ncipollo/release-action@v1
         with:
           tag: ${{ needs.plan.outputs.tag }}
diff --git a/Cargo.lock b/Cargo.lock
index 942cf7fd..92c14e4f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,12 +17,21 @@ name = "addr2line"
 version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli 0.28.1",
+]
+
+[[package]]
+name = "addr2line"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
 dependencies = [
  "cpp_demangle",
  "fallible-iterator",
- "gimli",
+ "gimli 0.29.0",
  "memmap2",
- "object 0.32.2",
+ "object 0.35.0",
  "rustc-demangle",
  "smallvec",
 ]
@@ -52,7 +61,7 @@ checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
 dependencies = [
  "getrandom",
  "once_cell",
- "version_check 0.9.4",
+ "version_check",
 ]
 
 [[package]]
@@ -63,7 +72,7 @@ checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
 dependencies = [
  "cfg-if",
  "once_cell",
- "version_check 0.9.4",
+ "version_check",
  "zerocopy",
 ]
 
@@ -78,18 +87,18 @@ dependencies = [
 
 [[package]]
 name = "allocator-api2"
-version = "0.2.16"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
 
 [[package]]
 name = "ansi-parser"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcb2392079bf27198570d6af79ecbd9ec7d8f16d3ec6b60933922fdb66287127"
+checksum = "fad5bd94a775101bd68c2de2bb28ca2eccd69f395ae3aec4ac4f6da3c1cd2c6a"
 dependencies = [
- "heapless 0.5.6",
- "nom 4.2.3",
+ "heapless 0.6.1",
+ "nom",
 ]
 
 [[package]]
@@ -142,9 +151,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.81"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
+checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
 
 [[package]]
 name = "arrayvec"
@@ -232,13 +241,13 @@ dependencies = [
 
 [[package]]
 name = "async-trait"
-version = "0.1.79"
+version = "0.1.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681"
+checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -258,9 +267,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
 [[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
 
 [[package]]
 name = "backtrace"
@@ -268,7 +277,7 @@ version = "0.3.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
 dependencies = [
- "addr2line",
+ "addr2line 0.21.0",
  "cc",
  "cfg-if",
  "libc",
@@ -306,9 +315,9 @@ dependencies = [
 
 [[package]]
 name = "bitfield"
-version = "0.14.0"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
+checksum = "c821a6e124197eb56d907ccc2188eab1038fb919c914f47976e64dd8dbc855d1"
 
 [[package]]
 name = "bitflags"
@@ -367,9 +376,9 @@ dependencies = [
 
 [[package]]
 name = "borsh"
-version = "1.3.1"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667"
+checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6"
 dependencies = [
  "borsh-derive",
  "cfg_aliases",
@@ -377,15 +386,15 @@ dependencies = [
 
 [[package]]
 name = "borsh-derive"
-version = "1.3.1"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd"
+checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5"
 dependencies = [
  "once_cell",
  "proc-macro-crate 3.1.0",
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
  "syn_derive",
 ]
 
@@ -402,9 +411,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.15.4"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "byte-unit"
@@ -456,7 +465,7 @@ checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -529,9 +538,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-config2"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42c11223b5229031d9b4ad2125ac8794386a2891a5c02acc4240bc46dd3af4f9"
+checksum = "88d9bdc858a15454c2d0a5138d8dcf4bcabc06fde679abdea8330393fbc0ef05"
 dependencies = [
  "home",
  "serde",
@@ -579,9 +588,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.90"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
+checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
 dependencies = [
  "jobserver",
  "libc",
@@ -601,9 +610,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
 
 [[package]]
 name = "chrono"
-version = "0.4.35"
+version = "0.4.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
 dependencies = [
  "num-traits",
 ]
@@ -620,9 +629,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.3"
+version = "4.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813"
+checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -637,19 +646,19 @@ dependencies = [
  "anstream",
  "anstyle",
  "clap_lex",
- "strsim 0.11.0",
+ "strsim 0.11.1",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.5.3"
+version = "4.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
+checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
 dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -927,9 +936,9 @@ dependencies = [
  "defmt-json-schema",
  "defmt-parser",
  "dissimilar",
- "gimli",
+ "gimli 0.28.1",
  "log",
- "nom 7.1.3",
+ "nom",
  "object 0.32.2",
  "ryu",
  "serde",
@@ -1072,7 +1081,7 @@ checksum = "4673f83edb6dfabfbc26704bd89ee95f4b164cd5db5fe8c88efda48fb0fca8d7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -1083,9 +1092,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
 
 [[package]]
 name = "either"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
 
 [[package]]
 name = "encode_unicode"
@@ -1095,9 +1104,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
 [[package]]
 name = "encoding_rs"
-version = "0.8.33"
+version = "0.8.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
+checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
 dependencies = [
  "cfg-if",
 ]
@@ -1117,7 +1126,7 @@ dependencies = [
  "heck 0.4.1",
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -1128,7 +1137,7 @@ checksum = "ba7795da175654fe16979af73f81f26a8ea27638d8d9823d317016888a63dc4c"
 dependencies = [
  "num-traits",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -1243,9 +1252,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
 
 [[package]]
 name = "fastrand"
-version = "2.0.1"
+version = "2.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
 
 [[package]]
 name = "fd-lock"
@@ -1260,9 +1269,9 @@ dependencies = [
 
 [[package]]
 name = "figment"
-version = "0.10.15"
+version = "0.10.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7270677e7067213e04f323b55084586195f18308cd7546cfac9f873344ccceb6"
+checksum = "fdefe49ed1057d124dc81a0681c30dd07de56ad96e32adc7b64e8f28eaab31c4"
 dependencies = [
  "atomic",
  "pear",
@@ -1271,7 +1280,7 @@ dependencies = [
  "serde_yaml",
  "toml",
  "uncased",
- "version_check 0.9.4",
+ "version_check",
 ]
 
 [[package]]
@@ -1383,7 +1392,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -1455,14 +1464,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
 dependencies = [
  "typenum",
- "version_check 0.9.4",
+ "version_check",
 ]
 
 [[package]]
 name = "getrandom"
-version = "0.2.12"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
 dependencies = [
  "cfg-if",
  "libc",
@@ -1479,6 +1488,16 @@ dependencies = [
  "stable_deref_trait",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+dependencies = [
+ "fallible-iterator",
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "git-version"
 version = "0.3.9"
@@ -1496,7 +1515,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -1509,7 +1528,7 @@ dependencies = [
  "bstr",
  "log",
  "regex-automata 0.4.6",
- "regex-syntax 0.8.2",
+ "regex-syntax 0.8.3",
 ]
 
 [[package]]
@@ -1592,12 +1611,12 @@ dependencies = [
 
 [[package]]
 name = "heapless"
-version = "0.5.6"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74911a68a1658cfcfb61bc0ccfbd536e3b6e906f8c2f7883ee50157e3e2184f1"
+checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
 dependencies = [
  "as-slice",
- "generic-array 0.13.3",
+ "generic-array 0.14.7",
  "hash32 0.1.1",
  "stable_deref_trait",
 ]
@@ -1830,9 +1849,9 @@ dependencies = [
 
 [[package]]
 name = "hyper"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a"
+checksum = "9f24ce812868d86d19daa79bf3bf9175bc44ea323391147a5e3abde2a283871b"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -1869,9 +1888,9 @@ checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
 dependencies = [
  "futures-util",
  "http 1.1.0",
- "hyper 1.2.0",
+ "hyper 1.3.0",
  "hyper-util",
- "rustls 0.22.2",
+ "rustls 0.22.3",
  "rustls-pki-types",
  "tokio",
  "tokio-rustls 0.25.0",
@@ -1889,7 +1908,7 @@ dependencies = [
  "futures-util",
  "http 1.1.0",
  "http-body 1.0.0",
- "hyper 1.2.0",
+ "hyper 1.3.0",
  "pin-project-lite",
  "socket2",
  "tokio",
@@ -2043,7 +2062,7 @@ dependencies = [
  "socket2",
  "widestring",
  "windows-sys 0.48.0",
- "winreg",
+ "winreg 0.50.0",
 ]
 
 [[package]]
@@ -2100,9 +2119,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "jep106"
@@ -2115,9 +2134,9 @@ dependencies = [
 
 [[package]]
 name = "jobserver"
-version = "0.1.28"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
+checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2"
 dependencies = [
  "libc",
 ]
@@ -2145,20 +2164,19 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
 name = "libredox"
-version = "0.0.1"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
  "bitflags 2.5.0",
  "libc",
- "redox_syscall",
 ]
 
 [[package]]
 name = "libtest-mimic"
-version = "0.7.0"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f0f4c6f44ecfd52e8b443f2ad18f2b996540135771561283c2352ce56a1c70b"
+checksum = "fefdf21230d6143476a28adbee3d930e2b68a3d56443c777cae3fe9340eebff9"
 dependencies = [
  "clap",
  "escape8259",
@@ -2199,7 +2217,7 @@ checksum = "adf157a4dc5a29b7b464aa8fe7edeff30076e07e13646a1c3874f58477dc99f8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -2293,15 +2311,15 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
 
 [[package]]
 name = "memchr"
-version = "2.7.1"
+version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
 [[package]]
 name = "memmap2"
-version = "0.5.10"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
+checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
 dependencies = [
  "libc",
 ]
@@ -2326,7 +2344,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -2403,16 +2421,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "nom"
-version = "4.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
-dependencies = [
- "memchr",
- "version_check 0.1.5",
-]
-
 [[package]]
 name = "nom"
 version = "7.1.3"
@@ -2502,18 +2510,18 @@ version = "0.32.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
 dependencies = [
- "flate2",
  "memchr",
- "ruzstd",
 ]
 
 [[package]]
 name = "object"
-version = "0.34.0"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7090bae93f8585aad99e595b7073c5de9ba89fbd6b4e9f0cdd7a10177273ac8"
+checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
 dependencies = [
+ "flate2",
  "memchr",
+ "ruzstd",
 ]
 
 [[package]]
@@ -2627,7 +2635,7 @@ dependencies = [
  "proc-macro2",
  "proc-macro2-diagnostics",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -2653,14 +2661,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "pin-utils"
@@ -2682,12 +2690,13 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
 
 [[package]]
 name = "polling"
-version = "3.5.0"
+version = "3.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9"
+checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6"
 dependencies = [
  "cfg-if",
  "concurrent-queue",
+ "hermit-abi",
  "pin-project-lite",
  "rustix",
  "tracing",
@@ -2766,7 +2775,7 @@ dependencies = [
 name = "probe-rs"
 version = "0.23.0"
 dependencies = [
- "addr2line",
+ "addr2line 0.22.0",
  "ansi-parser",
  "anyhow",
  "async-io",
@@ -2793,7 +2802,7 @@ dependencies = [
  "figment",
  "futures-lite",
  "gdbstub",
- "gimli",
+ "gimli 0.29.0",
  "git-version",
  "goblin",
  "hexdump",
@@ -2808,7 +2817,7 @@ dependencies = [
  "miniz_oxide",
  "num-traits",
  "nusb",
- "object 0.34.0",
+ "object 0.35.0",
  "once_cell",
  "parking_lot",
  "parse_int",
@@ -2879,7 +2888,7 @@ dependencies = [
  "proc-macro-error-attr",
  "proc-macro2",
  "quote",
- "version_check 0.9.4",
+ "version_check",
 ]
 
 [[package]]
@@ -2890,14 +2899,14 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
 dependencies = [
  "proc-macro2",
  "quote",
- "version_check 0.9.4",
+ "version_check",
 ]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.79"
+version = "1.0.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
+checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e"
 dependencies = [
  "unicode-ident",
 ]
@@ -2910,8 +2919,8 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
- "version_check 0.9.4",
+ "syn 2.0.59",
+ "version_check",
  "yansi 1.0.1",
 ]
 
@@ -2952,9 +2961,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
@@ -3007,9 +3016,9 @@ dependencies = [
 
 [[package]]
 name = "ratatui"
-version = "0.26.1"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcb12f8fbf6c62614b0d56eb352af54f6a22410c3b079eb53ee93c7b97dd31d8"
+checksum = "a564a852040e82671dc50a37d88f3aa83bbc690dfc6844cfe7a2591620206a80"
 dependencies = [
  "bitflags 2.5.0",
  "cassowary",
@@ -3036,9 +3045,9 @@ dependencies = [
 
 [[package]]
 name = "redox_users"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
+checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
 dependencies = [
  "getrandom",
  "libredox",
@@ -3054,7 +3063,7 @@ dependencies = [
  "aho-corasick",
  "memchr",
  "regex-automata 0.4.6",
- "regex-syntax 0.8.2",
+ "regex-syntax 0.8.3",
 ]
 
 [[package]]
@@ -3074,7 +3083,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-syntax 0.8.2",
+ "regex-syntax 0.8.3",
 ]
 
 [[package]]
@@ -3085,9 +3094,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
 
 [[package]]
 name = "rend"
@@ -3124,7 +3133,7 @@ dependencies = [
  "pin-project-lite",
  "rustls 0.21.10",
  "rustls-native-certs",
- "rustls-pemfile",
+ "rustls-pemfile 1.0.4",
  "serde",
  "serde_json",
  "serde_urlencoded",
@@ -3139,23 +3148,23 @@ dependencies = [
  "wasm-bindgen-futures",
  "wasm-streams",
  "web-sys",
- "winreg",
+ "winreg 0.50.0",
 ]
 
 [[package]]
 name = "reqwest"
-version = "0.12.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338"
+checksum = "3e6cc1e89e689536eb5aeede61520e874df5a4707df811cd5da4aa5fbb2aae19"
 dependencies = [
- "base64 0.21.7",
+ "base64 0.22.0",
  "bytes",
  "futures-core",
  "futures-util",
  "http 1.1.0",
  "http-body 1.0.0",
  "http-body-util",
- "hyper 1.2.0",
+ "hyper 1.3.0",
  "hyper-rustls 0.26.0",
  "hyper-util",
  "ipnet",
@@ -3165,8 +3174,8 @@ dependencies = [
  "once_cell",
  "percent-encoding",
  "pin-project-lite",
- "rustls 0.22.2",
- "rustls-pemfile",
+ "rustls 0.22.3",
+ "rustls-pemfile 2.1.2",
  "rustls-pki-types",
  "serde",
  "serde_json",
@@ -3180,7 +3189,7 @@ dependencies = [
  "wasm-bindgen-futures",
  "web-sys",
  "webpki-roots",
- "winreg",
+ "winreg 0.52.0",
 ]
 
 [[package]]
@@ -3277,9 +3286,9 @@ dependencies = [
 
 [[package]]
 name = "rust_decimal"
-version = "1.34.3"
+version = "1.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df"
+checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a"
 dependencies = [
  "arrayvec 0.7.4",
  "borsh",
@@ -3324,9 +3333,9 @@ dependencies = [
 
 [[package]]
 name = "rustls"
-version = "0.22.2"
+version = "0.22.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41"
+checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c"
 dependencies = [
  "log",
  "ring",
@@ -3343,7 +3352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
 dependencies = [
  "openssl-probe",
- "rustls-pemfile",
+ "rustls-pemfile 1.0.4",
  "schannel",
  "security-framework",
 ]
@@ -3357,11 +3366,21 @@ dependencies = [
  "base64 0.21.7",
 ]
 
+[[package]]
+name = "rustls-pemfile"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
+dependencies = [
+ "base64 0.22.0",
+ "rustls-pki-types",
+]
+
 [[package]]
 name = "rustls-pki-types"
-version = "1.4.0"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "868e20fada228fefaf6b652e00cc73623d54f8171e7352c18bb281571f2d92da"
+checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
 
 [[package]]
 name = "rustls-webpki"
@@ -3386,9 +3405,9 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.14"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
+checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
 
 [[package]]
 name = "rustyline"
@@ -3414,9 +3433,9 @@ dependencies = [
 
 [[package]]
 name = "ruzstd"
-version = "0.5.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d"
+checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b"
 dependencies = [
  "byteorder",
  "derive_more",
@@ -3523,7 +3542,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -3544,9 +3563,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
 
 [[package]]
 name = "security-framework"
-version = "2.9.2"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
+checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6"
 dependencies = [
  "bitflags 1.3.2",
  "core-foundation",
@@ -3557,9 +3576,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "2.9.1"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
+checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -3591,7 +3610,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -3616,13 +3635,13 @@ dependencies = [
 
 [[package]]
 name = "serde_repr"
-version = "0.1.18"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
+checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -3728,9 +3747,9 @@ checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
 
 [[package]]
 name = "similar"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21"
+checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
 
 [[package]]
 name = "slab"
@@ -3786,12 +3805,12 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
 
 [[package]]
 name = "stability"
-version = "0.1.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebd1b177894da2a2d9120208c3386066af06a488255caabc5de8ddca22dbc3ce"
+checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a"
 dependencies = [
  "quote",
- "syn 1.0.109",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -3814,9 +3833,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
 [[package]]
 name = "strsim"
-version = "0.11.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "strum"
@@ -3837,7 +3856,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -3888,9 +3907,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.53"
+version = "2.0.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
+checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3906,7 +3925,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -3959,7 +3978,7 @@ dependencies = [
  "predicates",
  "probe-rs",
  "probe-rs-target",
- "reqwest 0.12.2",
+ "reqwest 0.12.3",
  "scroll",
  "serde_yaml",
  "tokio",
@@ -4013,7 +4032,7 @@ dependencies = [
  "cfg-if",
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -4024,7 +4043,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
  "test-case-core",
 ]
 
@@ -4056,7 +4075,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -4080,9 +4099,9 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.34"
+version = "0.3.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
 dependencies = [
  "deranged",
  "itoa",
@@ -4103,9 +4122,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.17"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
 dependencies = [
  "num-conv",
  "time-core",
@@ -4151,7 +4170,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -4170,7 +4189,7 @@ version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
 dependencies = [
- "rustls 0.22.2",
+ "rustls 0.22.3",
  "rustls-pki-types",
  "tokio",
 ]
@@ -4242,7 +4261,7 @@ dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
- "winnow 0.6.5",
+ "winnow 0.6.6",
 ]
 
 [[package]]
@@ -4305,7 +4324,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -4412,7 +4431,7 @@ version = "0.9.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697"
 dependencies = [
- "version_check 0.9.4",
+ "version_check",
 ]
 
 [[package]]
@@ -4511,12 +4530,6 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
-[[package]]
-name = "version_check"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
-
 [[package]]
 name = "version_check"
 version = "0.9.4"
@@ -4578,7 +4591,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
  "wasm-bindgen-shared",
 ]
 
@@ -4612,7 +4625,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -4657,9 +4670,9 @@ dependencies = [
 
 [[package]]
 name = "widestring"
-version = "1.0.2"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
+checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
 
 [[package]]
 name = "winapi"
@@ -4707,7 +4720,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -4727,17 +4740,18 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.4",
- "windows_aarch64_msvc 0.52.4",
- "windows_i686_gnu 0.52.4",
- "windows_i686_msvc 0.52.4",
- "windows_x86_64_gnu 0.52.4",
- "windows_x86_64_gnullvm 0.52.4",
- "windows_x86_64_msvc 0.52.4",
+ "windows_aarch64_gnullvm 0.52.5",
+ "windows_aarch64_msvc 0.52.5",
+ "windows_i686_gnu 0.52.5",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.5",
+ "windows_x86_64_gnu 0.52.5",
+ "windows_x86_64_gnullvm 0.52.5",
+ "windows_x86_64_msvc 0.52.5",
 ]
 
 [[package]]
@@ -4748,9 +4762,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -4760,9 +4774,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -4772,9 +4786,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.4"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -4784,9 +4804,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -4796,9 +4816,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -4808,9 +4828,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -4820,9 +4840,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
 [[package]]
 name = "winnow"
@@ -4835,9 +4855,9 @@ dependencies = [
 
 [[package]]
 name = "winnow"
-version = "0.6.5"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
+checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
 dependencies = [
  "memchr",
 ]
@@ -4852,6 +4872,16 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "winreg"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "wyz"
 version = "0.5.1"
@@ -4872,18 +4902,18 @@ dependencies = [
 
 [[package]]
 name = "xshell"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad"
+checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e"
+checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
 
 [[package]]
 name = "xtask"
@@ -4933,7 +4963,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.53",
+ "syn 2.0.59",
 ]
 
 [[package]]
@@ -4983,9 +5013,9 @@ dependencies = [
 
 [[package]]
 name = "zstd-sys"
-version = "2.0.9+zstd.1.5.5"
+version = "2.0.10+zstd.1.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
+checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
 dependencies = [
  "cc",
  "pkg-config",
diff --git a/Cargo.toml b/Cargo.toml
index 6ca86b14..2c0f6e0c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,7 +27,7 @@ probe-rs-target = { path = "probe-rs-target", version = "0.23.0" }
 
 docsplay = "0.1.1"
 thiserror = "1.0.58"
-anyhow = "1.0.81"
+anyhow = "1.0.82"
 
 [workspace.metadata.release]
 shared-version = true
@@ -36,11 +36,11 @@ tag-name = "v{{version}}"
 # Config for 'cargo dist'
 [workspace.metadata.dist]
 # The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax)
-cargo-dist-version = "0.11.1"
+cargo-dist-version = "0.13.0"
 # CI backends to support
 ci = ["github"]
 # Target platforms to build apps for (Rust target-triple syntax)
-targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
+targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
 # Build only the required packages, and individually
 precise-builds = true
 # The archive format to use for non-windows builds (defaults .tar.xz)
@@ -53,6 +53,8 @@ pr-run-mode = "plan"
 tap = "probe-rs/homebrew-probe-rs"
 # Publish jobs to run in CI
 publish-jobs = ["homebrew"]
+# Whether to install an updater program
+install-updater = false
 # Select custom runner for ARM Linux
 [workspace.metadata.dist.github-custom-runners]
 aarch64-unknown-linux-gnu = "buildjet-2vcpu-ubuntu-2204-arm"
diff --git a/changelog/added-dap-server-ip-option.md b/changelog/added-dap-server-ip-option.md
new file mode 100644
index 00000000..90cbd2ab
--- /dev/null
+++ b/changelog/added-dap-server-ip-option.md
@@ -0,0 +1,1 @@
+Users can now specify IP address for dap-server to bind.
diff --git a/changelog/added-enable-kickstart-power-for-jlink.md b/changelog/added-enable-kickstart-power-for-jlink.md
new file mode 100644
index 00000000..63349185
--- /dev/null
+++ b/changelog/added-enable-kickstart-power-for-jlink.md
@@ -0,0 +1,1 @@
+added enable/disable kickstart power for J-Link
diff --git a/changelog/added-new stm32-targets.md b/changelog/added-new stm32-targets.md
new file mode 100644
index 00000000..d5c84bae
--- /dev/null
+++ b/changelog/added-new stm32-targets.md
@@ -0,0 +1,1 @@
+Update the `STM32WB_Series.yaml` targets with `target-gen arm --filter STM32WBxx_DFP`
diff --git a/changelog/added-u0.md b/changelog/added-u0.md
new file mode 100644
index 00000000..cde132bc
--- /dev/null
+++ b/changelog/added-u0.md
@@ -0,0 +1,1 @@
+Added support for STM32U0 devices
\ No newline at end of file
diff --git a/changelog/changed-cmd-info-default-dp.md b/changelog/changed-cmd-info-default-dp.md
new file mode 100644
index 00000000..bdeaa91f
--- /dev/null
+++ b/changelog/changed-cmd-info-default-dp.md
@@ -0,0 +1,1 @@
+Only enumerate alternate multi-drop addresses if the Default address failed
diff --git a/changelog/fixed-lpc55s69-load-secure-flash.md b/changelog/fixed-lpc55s69-load-secure-flash.md
new file mode 100644
index 00000000..ed727f9f
--- /dev/null
+++ b/changelog/fixed-lpc55s69-load-secure-flash.md
@@ -0,0 +1,1 @@
+Fixed so that secure flash area on LPC55S69 can be loaded.
diff --git a/changelog/removed-rtt-feature.md b/changelog/removed-rtt-feature.md
new file mode 100644
index 00000000..eda3ca48
--- /dev/null
+++ b/changelog/removed-rtt-feature.md
@@ -0,0 +1,1 @@
+Removed the `rtt` cargo feature
\ No newline at end of file
diff --git a/probe-rs/Cargo.toml b/probe-rs/Cargo.toml
index e552b5a9..1031efdd 100644
--- a/probe-rs/Cargo.toml
+++ b/probe-rs/Cargo.toml
@@ -32,13 +32,11 @@ name = "cargo-embed"
 required-features = ["cli"]
 
 [features]
-default = ["builtin-targets", "rtt"]
+default = ["builtin-targets"]
 gdb-server = ["dep:gdbstub", "dep:itertools"]
-rtt = []
 
 cli = [
     "gdb-server",
-    "rtt",
 
     "dep:byte-unit",
     "dep:capstone",
@@ -84,11 +82,11 @@ test = []
 anyhow = { workspace = true }
 base64 = "0.22"
 bincode = "1.3"
-bitfield = "0.14"
+bitfield = "0.15"
 bitvec = "1"
 docsplay = { workspace = true }
 enum-primitive-derive = "0.3"
-gimli = { version = "0.28", default-features = false, features = [
+gimli = { version = "0.29", default-features = false, features = [
     "endian-reader",
     "read",
     "std",
@@ -101,7 +99,7 @@ jep106 = "0.2"
 once_cell = "1"
 miniz_oxide = "0.7"
 num-traits = "0.2"
-object = { version = "0.34", default-features = false, features = [
+object = { version = "0.35", default-features = false, features = [
     "elf",
     "read_core",
     "std",
@@ -135,7 +133,7 @@ gdbstub = { version = "0.7", optional = true }
 itertools = { version = "0.12", optional = true }
 
 # CLI-only
-addr2line = { version = "0.21", optional = true }
+addr2line = { version = "0.22", optional = true }
 byte-unit = { version = "5", optional = true }
 bytesize = { version = "1", optional = true }
 capstone = { version = "0.12", optional = true }
@@ -157,7 +155,7 @@ goblin = { version = "0.8", optional = true }
 indicatif = { version = "0.17", optional = true }
 insta = { version = "1.38", features = ["yaml", "filters"], optional = true }
 itm = { version = "0.9.0-rc.1", default-features = false, optional = true }
-libtest-mimic = { version = "0.7.0", optional = true }
+libtest-mimic = { version = "0.7.2", optional = true }
 rand = { version = "0.8", optional = true }
 rustyline = { version = "14", optional = true }
 sanitize-filename = { version = "0.5", optional = true }
@@ -179,12 +177,12 @@ tracing-subscriber = { version = "0.3", features = [
     "json",
 ], optional = true }
 tracing-appender = { version = "0.2", optional = true }
-ratatui = { version = "0.26.1", default-features = false, features = [
+ratatui = { version = "0.26.2", default-features = false, features = [
     "crossterm",
 ], optional = true }
-ansi-parser = { version = "0.8.0", optional = true }
+ansi-parser = { version = "0.9.0", optional = true }
 parking_lot = "0.12.1"
-cargo-config2 = { version = "0.1.23", optional = true }
+cargo-config2 = { version = "0.1.24", optional = true }
 
 [build-dependencies]
 bincode = "1"
diff --git a/probe-rs/build.rs b/probe-rs/build.rs
index 91390352..320e05a8 100644
--- a/probe-rs/build.rs
+++ b/probe-rs/build.rs
@@ -7,7 +7,7 @@ use probe_rs_target::ChipFamily;
 
 fn main() {
     #[cfg(feature = "cli")]
-    generate_meta();
+    generate_bin_versions();
     println!("cargo:rerun-if-changed=build.rs");
 
     // Only rerun build.rs if something inside targets/ or `PROBE_RS_TARGETS_DIR`
@@ -84,35 +84,11 @@ fn visit_dirs(dir: &Path, targets: &mut Vec<PathBuf>) -> io::Result<()> {
     Ok(())
 }
 
-/// Generates a `meta.rs` file in a crates `OUT_DIR`.
-///
-/// This is intended to be used in the `build.rs` of a crate.
-///
-///
-///
-/// # Examples
-///
-/// ```no_run
-/// crate::util::meta::generate_meta();
-/// println!("cargo:rerun-if-changed=build.rs");
-/// ```
 #[cfg(feature = "cli")]
-pub fn generate_meta() {
+fn generate_bin_versions() {
     const CARGO_VERSION: &str = env!("CARGO_PKG_VERSION");
     const GIT_VERSION: &str = git_version::git_version!(fallback = "crates.io");
-    let long_version: String = format!("{CARGO_VERSION}\ngit commit: {GIT_VERSION}");
-
-    let out_dir = std::env::var_os("OUT_DIR").unwrap();
-    let dest_path = std::path::Path::new(&out_dir).join("meta.rs");
-    std::fs::write(
-        dest_path,
-        format!(
-            r#"#[allow(dead_code)]mod meta {{
-pub const CARGO_VERSION: &str = "{CARGO_VERSION}";
-pub const GIT_VERSION: &str = "{GIT_VERSION}";
-pub const LONG_VERSION: &str = "{long_version}";
-}}        "#
-        ),
-    )
-    .unwrap();
+
+    println!("cargo:rustc-env=PROBE_RS_VERSION={CARGO_VERSION}");
+    println!("cargo:rustc-env=PROBE_RS_LONG_VERSION={CARGO_VERSION} (git commit: {GIT_VERSION})");
 }
diff --git a/probe-rs/src/bin/probe-rs/cmd/cargo_embed/mod.rs b/probe-rs/src/bin/probe-rs/cmd/cargo_embed/mod.rs
index 011f2ee1..05dcb745 100644
--- a/probe-rs/src/bin/probe-rs/cmd/cargo_embed/mod.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/cargo_embed/mod.rs
@@ -3,14 +3,16 @@ mod error;
 mod rttui;
 
 use anyhow::{anyhow, Context, Result};
-use clap::{CommandFactory, FromArgMatches};
+use clap::Parser;
 use colored::*;
 use parking_lot::FairMutex;
 use probe_rs::gdb_server::GdbInstanceConfiguration;
 use probe_rs::probe::list::Lister;
 use probe_rs::rtt::ScanRegion;
 use probe_rs::{probe::DebugProbeSelector, Session};
+use probe_rs_target::MemoryRegion;
 use std::ffi::OsString;
+use std::fs;
 use std::{
     fs::File,
     io::Write,
@@ -26,13 +28,20 @@ use crate::util::cargo::target_instruction_set;
 use crate::util::common_options::{BinaryDownloadOptions, OperationError, ProbeOptions};
 use crate::util::flash::{build_loader, run_flash_download};
 use crate::util::logging::setup_logging;
-use crate::util::rtt::{self, RttActiveTarget, RttChannelConfig, RttConfig};
+use crate::util::rtt::{
+    self, try_attach_to_rtt_shared, DefmtState, RttActiveTarget, RttChannelConfig, RttConfig,
+};
 use crate::util::{cargo::build_artifact, common_options::CargoOptions, logging, rtt::DataFormat};
 use crate::FormatOptions;
 
 #[derive(Debug, clap::Parser)]
-#[command(after_long_help = CargoOptions::help_message("cargo embed"))]
-#[command(bin_name = "cargo embed", display_name = "cargo-embed")]
+#[clap(
+    name = "cargo embed",
+    bin_name = "cargo embed",
+    version = env!("PROBE_RS_VERSION"),
+    long_version = env!("PROBE_RS_LONG_VERSION"),
+    after_long_help = CargoOptions::help_message("cargo embed")
+)]
 struct CliOptions {
     /// Name of the configuration profile to use.
     #[arg()]
@@ -97,14 +106,7 @@ fn main_try(mut args: Vec<OsString>, offset: UtcOffset) -> Result<()> {
     }
 
     // Parse the commandline options.
-    let opt = {
-        let matches = CliOptions::command()
-            .version(crate::meta::CARGO_VERSION)
-            .long_version(crate::meta::LONG_VERSION)
-            .get_matches_from(&args);
-
-        CliOptions::from_arg_matches(&matches)?
-    };
+    let opt = CliOptions::parse_from(&args);
 
     // Change the work dir if the user asked to do so.
     if let Some(ref work_dir) = opt.work_dir {
@@ -377,10 +379,16 @@ fn run_rttui_app(
         }
     }
 
-    let Some(rtt) = rtt_attach(
+    let memory_map = {
+        let session_handle = session.lock();
+        session_handle.target().memory_map.clone()
+    };
+
+    let Some(rtt) = attach_to_rtt_shared(
         session,
         core_id,
         config.rtt.timeout,
+        &memory_map,
         &ScanRegion::Ram,
         elf_path,
         &rtt_config,
@@ -446,13 +454,12 @@ fn run_rttui_app(
     }
 }
 
-/// Try to attach to RTT, with the given timeout
-// TODO: this is largely the same as `cmd::run::attach_to_rtt`. If we can figure out how to get
-// around the mutex issue required here, we should try to merge them.
-fn rtt_attach(
+#[allow(clippy::too_many_arguments)]
+fn attach_to_rtt_shared(
     session: &FairMutex<Session>,
     core_id: usize,
     timeout: Duration,
+    memory_map: &[MemoryRegion],
     rtt_region: &ScanRegion,
     elf_file: &Path,
     rtt_config: &RttConfig,
@@ -461,56 +468,21 @@ fn rtt_attach(
     // Try to find the RTT control block symbol in the ELF file.
     // If we find it, we can use the exact address to attach to the RTT control block. Otherwise, we
     // fall back to the caller-provided scan regions.
-    let mut file = File::open(elf_file)?;
-    let scan_region = if let Some(address) = RttActiveTarget::get_rtt_symbol(&mut file) {
+    let elf = fs::read(elf_file)?;
+    let scan_region = if let Some(address) = RttActiveTarget::get_rtt_symbol_from_bytes(&elf) {
         ScanRegion::Exact(address as u32)
     } else {
         rtt_region.clone()
     };
 
-    let t = std::time::Instant::now();
-    let mut rtt_init_attempt = 1;
-    let mut last_error = None;
-    while t.elapsed() < timeout {
-        tracing::debug!("Initializing RTT (attempt {})...", rtt_init_attempt);
-        rtt_init_attempt += 1;
-
-        // Lock the session mutex in a block, so it gets dropped as soon as possible.
-        //
-        // GDB is also using the session
-        {
-            let mut session_handle = session.lock();
-            let memory_map = session_handle.target().memory_map.clone();
-            let mut core = session_handle.core(core_id)?;
-
-            match rtt::attach_to_rtt(&mut core, &memory_map, &scan_region) {
-                Ok(Some(rtt)) => {
-                    let app = RttActiveTarget::new(
-                        &mut core,
-                        rtt,
-                        elf_file,
-                        rtt_config,
-                        timestamp_offset,
-                    );
-
-                    match app {
-                        Ok(app) => return Ok(Some(app)),
-                        Err(error) => last_error = Some(error),
-                    }
-                }
-                Ok(None) => return Ok(None),
-                Err(e) => last_error = Some(e),
-            }
-        }
+    let rtt = try_attach_to_rtt_shared(session, core_id, memory_map, timeout, &scan_region)?;
 
-        tracing::debug!("Failed to initialize RTT. Retrying until timeout.");
-        std::thread::sleep(Duration::from_millis(10));
-    }
+    let Some(rtt) = rtt else {
+        return Ok(None);
+    };
+    let mut session_handle = session.lock();
+    let mut core = session_handle.core(core_id)?;
 
-    // Timeout
-    if let Some(err) = last_error {
-        Err(err)
-    } else {
-        Err(anyhow!("Error setting up RTT"))
-    }
+    let defmt_state = DefmtState::try_from_bytes(&elf)?;
+    RttActiveTarget::new(&mut core, rtt, defmt_state, rtt_config, timestamp_offset).map(Some)
 }
diff --git a/probe-rs/src/bin/probe-rs/cmd/cargo_embed/rttui/channel.rs b/probe-rs/src/bin/probe-rs/cmd/cargo_embed/rttui/channel.rs
index 4ad3618f..d5eee755 100644
--- a/probe-rs/src/bin/probe-rs/cmd/cargo_embed/rttui/channel.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/cargo_embed/rttui/channel.rs
@@ -2,7 +2,7 @@ use std::net::SocketAddr;
 
 use crate::{
     cmd::cargo_embed::rttui::tcp::TcpPublisher,
-    util::rtt::{ChannelDataCallbacks, ChannelDataConfig, DefmtState, RttActiveUpChannel},
+    util::rtt::{ChannelDataCallbacks, DefmtState, RttActiveUpChannel},
 };
 
 pub enum ChannelData {
@@ -49,13 +49,12 @@ pub struct UpChannel {
 impl UpChannel {
     pub fn new(rtt_channel: RttActiveUpChannel, tcp_stream: Option<SocketAddr>) -> Self {
         Self {
-            data: match rtt_channel.data_format {
-                ChannelDataConfig::String { .. } | ChannelDataConfig::Defmt { .. } => {
-                    ChannelData::Strings {
-                        messages: Vec::new(),
-                    }
+            data: if rtt_channel.data_format.is_binary() {
+                ChannelData::Binary { data: Vec::new() }
+            } else {
+                ChannelData::Strings {
+                    messages: Vec::new(),
                 }
-                ChannelDataConfig::BinaryLE => ChannelData::Binary { data: Vec::new() },
             },
             tcp_stream: tcp_stream.map(TcpPublisher::new),
             rtt_channel,
diff --git a/probe-rs/src/bin/probe-rs/cmd/cargo_flash/diagnostics.rs b/probe-rs/src/bin/probe-rs/cmd/cargo_flash/diagnostics.rs
index c87a431f..21bf6cae 100644
--- a/probe-rs/src/bin/probe-rs/cmd/cargo_flash/diagnostics.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/cargo_flash/diagnostics.rs
@@ -240,11 +240,7 @@ fn generate_flash_error_hints(
     (
         error.to_string(),
         match error {
-            FlashError::NoSuitableNvm {
-                start: _,
-                end: _,
-                description_source,
-            } => {
+            FlashError::NoSuitableNvm { description_source, .. } => {
                 if &TargetDescriptionSource::Generic == description_source {
                     return (
                         error.to_string(),
@@ -273,9 +269,8 @@ fn generate_flash_error_hints(
                         MemoryRegion::Nvm(flash) => {
                             let _ = writeln!(
                                 hint_available_regions,
-                                "  {:#010x} - {:#010x} ({})",
-                                flash.range.start,
-                                flash.range.end,
+                                "  {:#010X?} ({})",
+                                flash.range,
                                 ByteSize(flash.range.end - flash.range.start)
                                     .to_string_as(true)
                             );
diff --git a/probe-rs/src/bin/probe-rs/cmd/cargo_flash/mod.rs b/probe-rs/src/bin/probe-rs/cmd/cargo_flash/mod.rs
index cf42dce0..71a9334b 100644
--- a/probe-rs/src/bin/probe-rs/cmd/cargo_flash/mod.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/cargo_flash/mod.rs
@@ -1,5 +1,6 @@
 mod diagnostics;
 
+use clap::Parser;
 use colored::*;
 use diagnostics::render_diagnostics;
 use probe_rs::probe::list::Lister;
@@ -12,14 +13,17 @@ use crate::util::common_options::{
 };
 use crate::util::flash;
 use crate::util::logging::{setup_logging, LevelFilter};
-use clap::{CommandFactory, FromArgMatches};
-
 use crate::util::{cargo::build_artifact, logging};
 
 /// Common options when flashing a target device.
 #[derive(Debug, clap::Parser)]
-#[command(after_long_help = CargoOptions::help_message("cargo flash"))]
-#[command(bin_name = "cargo flash", display_name = "cargo-flash")]
+#[clap(
+    name = "cargo flash",
+    bin_name = "cargo flash",
+    version = env!("PROBE_RS_VERSION"),
+    long_version = env!("PROBE_RS_LONG_VERSION"),
+    after_long_help = CargoOptions::help_message("cargo flash")
+)]
 struct CliOptions {
     /// Use this flag to reset and halt (instead of just a reset) the attached core after flashing the target.
     #[arg(long)]
@@ -77,14 +81,7 @@ fn main_try(mut args: Vec<OsString>, lister: &Lister) -> Result<(), OperationErr
     }
 
     // Parse the commandline options.
-    let opt = {
-        let matches = CliOptions::command()
-            .version(crate::meta::CARGO_VERSION)
-            .long_version(crate::meta::LONG_VERSION)
-            .get_matches_from(&args);
-
-        CliOptions::from_arg_matches(&matches)?
-    };
+    let opt = CliOptions::parse_from(&args);
 
     // Initialize the logger with the loglevel given on the commandline.
     let _log_guard = setup_logging(None, opt.log);
diff --git a/probe-rs/src/bin/probe-rs/cmd/dap_server/debug_adapter/dap/repl_commands.rs b/probe-rs/src/bin/probe-rs/cmd/dap_server/debug_adapter/dap/repl_commands.rs
index 85e1b70d..1bfa96b1 100644
--- a/probe-rs/src/bin/probe-rs/cmd/dap_server/debug_adapter/dap/repl_commands.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/dap_server/debug_adapter/dap/repl_commands.rs
@@ -458,10 +458,7 @@ pub(crate) static REPL_COMMANDS: &[ReplCommand<ReplHandler>] = &[
             };
             let mut range_string = String::new();
             for memory_range in &ranges {
-                range_string.push_str(&format!(
-                    "{:#x}..{:#x}, ",
-                    &memory_range.start, &memory_range.end
-                ));
+                range_string.push_str(&format!("{memory_range:#X?}, "));
             }
             if range_string.is_empty() {
                 range_string = "(No memory ranges specified)".to_string();
diff --git a/probe-rs/src/bin/probe-rs/cmd/dap_server/mod.rs b/probe-rs/src/bin/probe-rs/cmd/dap_server/mod.rs
index e62a9f45..8f811998 100644
--- a/probe-rs/src/bin/probe-rs/cmd/dap_server/mod.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/dap_server/mod.rs
@@ -14,7 +14,12 @@ use probe_rs::{
     probe::DebugProbeError, CoreDumpError, Error,
 };
 use server::startup::debug;
-use std::{fs::File, io::stderr, path::Path};
+use std::{
+    fs::File,
+    io::stderr,
+    net::{IpAddr, Ipv4Addr, SocketAddr},
+    path::Path,
+};
 use time::UtcOffset;
 use tracing::metadata::LevelFilter;
 use tracing_subscriber::{
@@ -75,6 +80,10 @@ pub struct Cmd {
     #[clap(long)]
     port: u16,
 
+    /// IP address to listen for incoming DAP connections, e.g. "127.0.0.1"
+    #[clap(long, default_value_t = Ipv4Addr::LOCALHOST.into())]
+    ip: IpAddr,
+
     /// Some editors and IDEs expect the debug adapter processes to exit at the end of every debug
     /// session (on receiving a `Disconnect` or `Terminate` request).
     ///
@@ -92,10 +101,11 @@ pub fn run(
     log_file: Option<&Path>,
 ) -> Result<()> {
     let log_info_message = setup_logging(log_file)?;
+    let addr = SocketAddr::new(cmd.ip, cmd.port);
 
     debug(
         lister,
-        cmd.port,
+        addr,
         cmd.single_session,
         &log_info_message,
         time_offset,
diff --git a/probe-rs/src/bin/probe-rs/cmd/dap_server/server/core_data.rs b/probe-rs/src/bin/probe-rs/cmd/dap_server/server/core_data.rs
index a616e2d2..ff24a3f7 100644
--- a/probe-rs/src/bin/probe-rs/cmd/dap_server/server/core_data.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/dap_server/server/core_data.rs
@@ -1,7 +1,7 @@
-use std::{fs::File, ops::Range, path::Path};
+use std::{ops::Range, path::Path};
 
 use super::session_data::{self, ActiveBreakpoint, BreakpointType, SourceLocationScope};
-use crate::util::rtt::{self, ChannelMode, DataFormat, RttActiveTarget};
+use crate::util::rtt::{self, DataFormat, DefmtState, RttActiveTarget};
 use crate::{
     cmd::dap_server::{
         debug_adapter::{
@@ -194,11 +194,6 @@ impl<'p> CoreHandle<'p> {
         };
 
         for up_channel in target_rtt.active_up_channels.values() {
-            let data_format = DataFormat::from(&up_channel.data_format);
-            if data_format == DataFormat::Defmt {
-                // For defmt, we set the channel to be blocking when full.
-                up_channel.set_mode(&mut self.core, ChannelMode::BlockIfFull)?;
-            }
             debugger_rtt_channels.push(debug_rtt::DebuggerRttChannel {
                 channel_number: up_channel.number(),
                 // This value will eventually be set to true by a VSCode client request "rttWindowOpened"
@@ -207,7 +202,7 @@ impl<'p> CoreHandle<'p> {
             debug_adapter.rtt_window(
                 up_channel.number(),
                 up_channel.channel_name.clone(),
-                data_format,
+                DataFormat::from(&up_channel.data_format),
             );
         }
 
@@ -437,10 +432,10 @@ fn try_attach_rtt(
     rtt_config: &RttConfig,
     timestamp_offset: UtcOffset,
 ) -> Result<RttActiveTarget, Error> {
-    let mut open_file = File::open(elf_file)
+    let elf = std::fs::read(elf_file)
         .map_err(|error| anyhow!("Error attempting to attach to RTT: {}", error))?;
 
-    let header_address = RttActiveTarget::get_rtt_symbol(&mut open_file)
+    let header_address = RttActiveTarget::get_rtt_symbol_from_bytes(&elf)
         .ok_or_else(|| anyhow!("No RTT control block found in ELF file"))?;
 
     let scan_region = ScanRegion::Exact(header_address as u32);
@@ -451,7 +446,8 @@ fn try_attach_rtt(
         .map_err(|error| anyhow!("Error attempting to attach to RTT: {}", error))?;
 
     tracing::info!("RTT initialized.");
-    let target = RttActiveTarget::new(core, rtt, elf_file, rtt_config, timestamp_offset)?;
+    let defmt_state = DefmtState::try_from_bytes(&elf)?;
+    let target = RttActiveTarget::new(core, rtt, defmt_state, rtt_config, timestamp_offset)?;
 
     Ok(target)
 }
diff --git a/probe-rs/src/bin/probe-rs/cmd/dap_server/server/startup.rs b/probe-rs/src/bin/probe-rs/cmd/dap_server/server/startup.rs
index 0befb351..670eed29 100644
--- a/probe-rs/src/bin/probe-rs/cmd/dap_server/server/startup.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/dap_server/server/startup.rs
@@ -5,7 +5,7 @@ use probe_rs::probe::list::Lister;
 use serde::Deserialize;
 use std::{
     fs,
-    net::{Ipv4Addr, TcpListener},
+    net::TcpListener,
     path::Path,
     time::{Duration, UNIX_EPOCH},
 };
@@ -33,7 +33,7 @@ impl std::str::FromStr for TargetSessionType {
 
 pub fn debug(
     lister: &Lister,
-    port: u16,
+    addr: std::net::SocketAddr,
     single_session: bool,
     log_info_message: &str,
     timestamp_offset: UtcOffset,
@@ -42,8 +42,6 @@ pub fn debug(
 
     log_to_console_and_tracing("Starting as a DAP Protocol server");
 
-    let addr = std::net::SocketAddr::new(std::net::IpAddr::V4(Ipv4Addr::LOCALHOST), port);
-
     // Tell the user if (and where) RUST_LOG messages are written.
     log_to_console_and_tracing(log_info_message);
 
diff --git a/probe-rs/src/bin/probe-rs/cmd/info.rs b/probe-rs/src/bin/probe-rs/cmd/info.rs
index 3b8256cc..f3295524 100644
--- a/probe-rs/src/bin/probe-rs/cmd/info.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/info.rs
@@ -85,8 +85,7 @@ impl Cmd {
     }
 }
 
-const DEFAULT_DP_ADRESSES: &[DpAddress] = &[
-    DpAddress::Default,
+const ALTERNATE_DP_ADRESSES: [DpAddress; 2] = [
     DpAddress::Multidrop(0x01002927),
     DpAddress::Multidrop(0x11002927),
 ];
@@ -111,30 +110,46 @@ fn try_show_info(
         return (probe, Err(e.into()));
     }
 
-    let mut probe = probe;
-
     if probe.has_arm_interface() {
-        let provided_target_sel;
-
-        let dp_addresses = if let Some(target_sel) = target_sel {
-            provided_target_sel = DpAddress::Multidrop(target_sel);
-            std::slice::from_ref(&provided_target_sel)
+        let dp_addr = if let Some(target_sel) = target_sel {
+            DpAddress::Multidrop(target_sel)
         } else {
-            DEFAULT_DP_ADRESSES
+            DpAddress::Default
         };
 
-        let mut dp_version = None;
-
-        for address in dp_addresses {
-            if let Some(dp_version) = dp_version {
-                if dp_version < DebugPortVersion::DPv2 && matches!(address, DpAddress::Multidrop(_))
-                {
-                    println!("Debug port version 1 does not support SWD multidrop. Skipping address {:?}.", address);
-                    continue;
+        let print_err = |dp_addr, e| {
+            println!(
+                "Error showing ARM chip information for Debug Port {:?}: {:?}",
+                dp_addr, e
+            );
+            println!();
+        };
+        match try_show_arm_dp_info(probe, dp_addr) {
+            (probe_moved, Ok(_)) => probe = probe_moved,
+            (probe_moved, Err(e)) => {
+                probe = probe_moved;
+                print_err(dp_addr, e);
+
+                if dp_addr == DpAddress::Default {
+                    println!("Trying alternate multi-drop debug ports");
+
+                    for address in ALTERNATE_DP_ADRESSES {
+                        match try_show_arm_dp_info(probe, address) {
+                            (probe_moved, Ok(dp_version)) => {
+                                probe = probe_moved;
+                                if dp_version < DebugPortVersion::DPv2 {
+                                    println!("Debug port version {} does not support SWD multidrop. Stopping here.", dp_version);
+                                    break;
+                                }
+                            }
+                            (probe_moved, Err(e)) => {
+                                probe = probe_moved;
+                                print_err(address, e);
+                            }
+                        }
+                    }
                 }
             }
-
-            (probe, dp_version) = show_arm_dp_info(probe, *address);
         }
     } else {
         println!("No DAP interface was found on the connected probe. ARM-specific information cannot be printed.");
@@ -197,39 +212,21 @@ fn try_show_info(
     (probe, Ok(()))
 }
 
-fn show_arm_dp_info(probe: Probe, dp_address: DpAddress) -> (Probe, Option<DebugPortVersion>) {
+fn try_show_arm_dp_info(probe: Probe, dp_address: DpAddress) -> (Probe, Result<DebugPortVersion>) {
     tracing::debug!("Trying to show ARM chip information");
-    match probe.try_into_arm_interface() {
-        Ok(interface) => match interface.initialize(DefaultArmSequence::create(), dp_address) {
-            Ok(mut interface) => {
-                let dp_version = show_arm_info(&mut *interface, dp_address)
-                    .inspect_err(|e| {
-                        println!("Error showing ARM chip information: {e:?}");
-                        println!();
-                    })
-                    .ok();
-                (interface.close(), dp_version)
-            }
-            Err((interface, e)) => {
-                println!(
-                    "Error showing ARM chip information for Debug Port {:?}: {:?}",
-                    dp_address,
-                    anyhow!(e)
-                );
-                println!();
-
-                (interface.close(), None)
-            }
-        },
-        Err((interface_probe, e)) => {
-            println!(
-                "Error showing ARM chip information for Debug Port {:?}: {:?}",
-                dp_address,
-                anyhow!(e)
-            );
-            println!();
-            (interface_probe, None)
+    match probe
+        .try_into_arm_interface()
+        .map_err(|(iface, e)| (iface, anyhow!(e)))
+        .and_then(|interface| {
+            interface
+                .initialize(DefaultArmSequence::create(), dp_address)
+                .map_err(|(interface, e)| (interface.close(), anyhow!(e)))
+        }) {
+        Ok(mut interface) => {
+            let res = show_arm_info(&mut *interface, dp_address);
+            (interface.close(), res)
         }
+        Err((probe, e)) => (probe, Err(e)),
     }
 }
 
diff --git a/probe-rs/src/bin/probe-rs/cmd/profile.rs b/probe-rs/src/bin/probe-rs/cmd/profile.rs
index 7f06a9ae..97f7c3a4 100644
--- a/probe-rs/src/bin/probe-rs/cmd/profile.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/profile.rs
@@ -1,6 +1,7 @@
 use std::collections::HashMap;
 use std::path::Path;
 use std::time::Duration;
+use std::time::Instant;
 
 use itm::TracePacket;
 use probe_rs::{
@@ -11,7 +12,6 @@ use probe_rs::{
     },
     probe::list::Lister,
 };
-use time::Instant;
 
 use addr2line::{
     gimli::{EndianRcSlice, RunTimeEndian},
@@ -117,7 +117,7 @@ impl ProfileCmd {
                     *samples.entry(pc).or_insert(1) += 1;
                     reads += 1;
                     core.run()?;
-                    if Instant::now() - start > duration {
+                    if start.elapsed() > duration {
                         break;
                     }
                 }
@@ -144,7 +144,7 @@ impl ProfileCmd {
                         *samples.entry(pc).or_insert(1) += 1;
                         reads += 1;
                     }
-                    if Instant::now() - start > duration {
+                    if start.elapsed() > duration {
                         break;
                     }
                 }
diff --git a/probe-rs/src/bin/probe-rs/cmd/run/mod.rs b/probe-rs/src/bin/probe-rs/cmd/run/mod.rs
index be822b72..39498fa7 100644
--- a/probe-rs/src/bin/probe-rs/cmd/run/mod.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/run/mod.rs
@@ -3,7 +3,7 @@ use normal_run_mode::*;
 mod test_run_mode;
 use test_run_mode::*;
 
-use std::fs::File;
+use std::fs::{self, File};
 use std::io::{Read, Write};
 use std::ops::Range;
 use std::path::Path;
@@ -25,7 +25,9 @@ use time::UtcOffset;
 
 use crate::util::common_options::{BinaryDownloadOptions, ProbeOptions};
 use crate::util::flash::{build_loader, run_flash_download};
-use crate::util::rtt::{self, ChannelDataCallbacks, RttActiveTarget, RttConfig};
+use crate::util::rtt::{
+    self, try_attach_to_rtt, ChannelDataCallbacks, DefmtState, RttActiveTarget, RttConfig,
+};
 use crate::FormatOptions;
 
 #[derive(clap::Parser)]
@@ -272,7 +274,7 @@ impl RunLoop {
             core,
             Duration::from_secs(1),
             self.memory_map.as_slice(),
-            self.rtt_scan_regions.as_slice(),
+            &ScanRegion::Ranges(self.rtt_scan_regions.clone()),
             Path::new(&self.path),
             &rtt_config,
             self.timestamp_offset,
@@ -295,11 +297,11 @@ impl RunLoop {
             }
         };
 
-        let mut return_reason = None;
-        while !exit.load(Ordering::Relaxed) && return_reason.is_none() {
+        let return_reason = loop {
             // check for halt first, poll rtt after.
             // this is important so we do one last poll after halt, so we flush all messages
             // the core printed before halting, such as a panic message.
+            let mut return_reason = None;
             match core.status()? {
                 probe_rs::CoreStatus::Halted(reason) => match predicate(reason, core) {
                     Ok(Some(r)) => return_reason = Some(Ok(ReturnReason::Predicate(r))),
@@ -319,13 +321,20 @@ impl RunLoop {
 
             let had_rtt_data = poll_rtt(&mut rtta, core, output_stream)?;
 
-            match timeout {
-                Some(timeout) if start.elapsed() >= timeout => {
-                    core.halt(Duration::from_secs(1))?;
-                    return_reason = Some(Ok(ReturnReason::Timeout));
-                    break;
+            if return_reason.is_none() {
+                if exit.load(Ordering::Relaxed) {
+                    return_reason = Some(Ok(ReturnReason::User));
                 }
-                _ => {}
+
+                if let Some(timeout) = timeout {
+                    if start.elapsed() >= timeout {
+                        return_reason = Some(Ok(ReturnReason::Timeout));
+                    }
+                }
+            }
+
+            if let Some(reason) = return_reason {
+                break reason;
             }
 
             // Poll RTT with a frequency of 10 Hz if we do not receive any new data.
@@ -338,21 +347,15 @@ impl RunLoop {
             } else {
                 std::thread::sleep(Duration::from_millis(100));
             }
-        }
-
-        let return_reason = match return_reason {
-            None => {
-                // manually halted with Control+C. Stop the core.
-                core.halt(Duration::from_secs(1))?;
-                Ok(ReturnReason::User)
-            }
-            Some(r) => r,
         };
 
         if self.always_print_stacktrace
             || return_reason.is_err()
             || matches!(return_reason, Ok(ReturnReason::Timeout))
         {
+            if !core.core_halted()? {
+                core.halt(Duration::from_secs(1))?;
+            }
             print_stacktrace(core, Path::new(&self.path), output_stream)?;
         }
 
@@ -470,55 +473,31 @@ fn poll_rtt<S: Write + ?Sized>(
     Ok(had_data)
 }
 
-/// Attach to the RTT buffers.
 fn attach_to_rtt(
     core: &mut Core<'_>,
     timeout: Duration,
     memory_map: &[MemoryRegion],
-    scan_regions: &[Range<u64>],
-    path: &Path,
+    rtt_region: &ScanRegion,
+    elf_file: &Path,
     rtt_config: &RttConfig,
     timestamp_offset: UtcOffset,
-) -> Result<Option<rtt::RttActiveTarget>> {
+) -> Result<Option<RttActiveTarget>> {
     // Try to find the RTT control block symbol in the ELF file.
     // If we find it, we can use the exact address to attach to the RTT control block. Otherwise, we
     // fall back to the caller-provided scan regions.
-    let mut file = File::open(path)?;
-    let scan_region = if let Some(address) = RttActiveTarget::get_rtt_symbol(&mut file) {
+    let elf = fs::read(elf_file)?;
+    let scan_region = if let Some(address) = RttActiveTarget::get_rtt_symbol_from_bytes(&elf) {
         ScanRegion::Exact(address as u32)
     } else {
-        ScanRegion::Ranges(scan_regions.to_vec())
+        rtt_region.clone()
     };
 
-    let t = std::time::Instant::now();
-    let mut rtt_init_attempt = 1;
-    let mut last_error = None;
-    while t.elapsed() < timeout {
-        tracing::debug!("Initializing RTT (attempt {})...", rtt_init_attempt);
-        rtt_init_attempt += 1;
-
-        match rtt::attach_to_rtt(core, memory_map, &scan_region) {
-            Ok(Some(target_rtt)) => {
-                let app =
-                    RttActiveTarget::new(core, target_rtt, path, rtt_config, timestamp_offset);
-
-                match app {
-                    Ok(app) => return Ok(Some(app)),
-                    Err(error) => last_error = Some(error),
-                }
-            }
-            Ok(None) => return Ok(None),
-            Err(e) => last_error = Some(e),
-        }
+    let rtt = try_attach_to_rtt(core, timeout, memory_map, &scan_region)?;
 
-        tracing::debug!("Failed to initialize RTT. Retrying until timeout.");
-        std::thread::sleep(std::time::Duration::from_millis(10));
-    }
+    let Some(rtt) = rtt else {
+        return Ok(None);
+    };
 
-    // Timeout
-    if let Some(err) = last_error {
-        Err(err)
-    } else {
-        Err(anyhow!("Error setting up RTT"))
-    }
+    let defmt_state = DefmtState::try_from_bytes(&elf)?;
+    RttActiveTarget::new(core, rtt, defmt_state, rtt_config, timestamp_offset).map(Some)
 }
diff --git a/probe-rs/src/bin/probe-rs/main.rs b/probe-rs/src/bin/probe-rs/main.rs
index 2d93421c..c8c31eea 100644
--- a/probe-rs/src/bin/probe-rs/main.rs
+++ b/probe-rs/src/bin/probe-rs/main.rs
@@ -1,8 +1,6 @@
 mod cmd;
 mod util;
 
-include!(concat!(env!("OUT_DIR"), "/meta.rs"));
-
 use std::cmp::Reverse;
 use std::ffi::OsStr;
 use std::fs;
@@ -30,8 +28,8 @@ const MAX_LOG_FILES: usize = 20;
 #[clap(
     name = "probe-rs",
     about = "The probe-rs CLI",
-    version = meta::CARGO_VERSION,
-    long_version = meta::LONG_VERSION
+    version = env!("PROBE_RS_VERSION"),
+    long_version = env!("PROBE_RS_LONG_VERSION")
 )]
 struct Cli {
     /// Location for log file
diff --git a/probe-rs/src/bin/probe-rs/util/rtt.rs b/probe-rs/src/bin/probe-rs/util/rtt.rs
index bb2ffbaf..4f1629c4 100644
--- a/probe-rs/src/bin/probe-rs/util/rtt.rs
+++ b/probe-rs/src/bin/probe-rs/util/rtt.rs
@@ -8,12 +8,14 @@ use probe_rs_target::MemoryRegion;
 use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
 use std::fs::File;
+use std::path::PathBuf;
+use std::time::{Duration, Instant};
 use std::{
     fmt,
     fmt::Write,
-    fs,
     io::{Read, Seek},
     path::Path,
+    thread,
 };
 use time::{macros::format_description, OffsetDateTime, UtcOffset};
 
@@ -51,7 +53,7 @@ pub fn get_target_core_id(session: &mut Session, elf_file: impl AsRef<Path>) ->
 /// Try to find the RTT control block in the ELF file and attach to it.
 ///
 /// This function can return `Ok(None)` to indicate that RTT is not available on the target.
-pub fn attach_to_rtt(
+fn attach_to_rtt(
     core: &mut Core,
     memory_map: &[MemoryRegion],
     rtt_region: &ScanRegion,
@@ -153,7 +155,7 @@ pub struct RttDownChannelConfig {
     pub operating_mode: Option<String>,
 }
 
-pub enum ChannelDataConfig {
+pub enum ChannelDataFormat {
     String {
         /// UTC offset used for creating timestamps, if enabled.
         ///
@@ -165,23 +167,25 @@ pub enum ChannelDataConfig {
     BinaryLE,
     Defmt {
         formatter: Formatter,
+        // CWD to strip from file paths in defmt output
+        cwd: PathBuf,
     },
 }
 
-impl From<&ChannelDataConfig> for DataFormat {
-    fn from(config: &ChannelDataConfig) -> Self {
+impl From<&ChannelDataFormat> for DataFormat {
+    fn from(config: &ChannelDataFormat) -> Self {
         match config {
-            ChannelDataConfig::String { .. } => DataFormat::String,
-            ChannelDataConfig::BinaryLE => DataFormat::BinaryLE,
-            ChannelDataConfig::Defmt { .. } => DataFormat::Defmt,
+            ChannelDataFormat::String { .. } => DataFormat::String,
+            ChannelDataFormat::BinaryLE => DataFormat::BinaryLE,
+            ChannelDataFormat::Defmt { .. } => DataFormat::Defmt,
         }
     }
 }
 
-impl std::fmt::Debug for ChannelDataConfig {
+impl std::fmt::Debug for ChannelDataFormat {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
-            ChannelDataConfig::String {
+            ChannelDataFormat::String {
                 timestamp_offset,
                 last_line_done,
             } => f
@@ -189,12 +193,136 @@ impl std::fmt::Debug for ChannelDataConfig {
                 .field("timestamp_offset", timestamp_offset)
                 .field("last_line_done", last_line_done)
                 .finish(),
-            ChannelDataConfig::BinaryLE => f.debug_struct("BinaryLE").finish(),
-            ChannelDataConfig::Defmt { .. } => f.debug_struct("Defmt").finish_non_exhaustive(),
+            ChannelDataFormat::BinaryLE => f.debug_struct("BinaryLE").finish(),
+            ChannelDataFormat::Defmt { .. } => f.debug_struct("Defmt").finish_non_exhaustive(),
         }
     }
 }
 
+impl ChannelDataFormat {
+    /// Returns whether the channel is expected to output binary data (`true`)
+    /// or human-readable strings (`false`).
+    pub fn is_binary(&self) -> bool {
+        matches!(self, ChannelDataFormat::BinaryLE)
+    }
+
+    fn process(
+        &mut self,
+        number: usize,
+        buffer: &[u8],
+        defmt_state: Option<&DefmtState>,
+        collector: &mut impl ChannelDataCallbacks,
+    ) -> Result<()> {
+        // FIXME: clean this up by splitting the enum variants out into separate structs
+        match self {
+            ChannelDataFormat::BinaryLE => collector.on_binary_data(number, buffer),
+            ChannelDataFormat::String {
+                timestamp_offset,
+                ref mut last_line_done,
+            } => {
+                let string = Self::process_string(buffer, *timestamp_offset, last_line_done)?;
+                collector.on_string_data(number, string)
+            }
+            ChannelDataFormat::Defmt {
+                ref formatter,
+                ref cwd,
+            } => {
+                let string = Self::process_defmt(buffer, defmt_state, formatter, cwd)?;
+                collector.on_string_data(number, string)
+            }
+        }
+    }
+
+    fn process_string(
+        buffer: &[u8],
+        offset: Option<UtcOffset>,
+        last_line_done: &mut bool,
+    ) -> Result<String> {
+        let incoming = String::from_utf8_lossy(buffer);
+
+        let Some(offset) = offset else {
+            return Ok(incoming.to_string());
+        };
+
+        let timestamp = OffsetDateTime::now_utc()
+            .to_offset(offset)
+            .format(format_description!(
+                "[hour repr:24]:[minute]:[second].[subsecond digits:3]"
+            ))?;
+
+        let mut formatted_data = String::new();
+        for line in incoming.split_inclusive('\n') {
+            if *last_line_done {
+                write!(formatted_data, "{timestamp}: ").expect("Writing to String cannot fail");
+            }
+            write!(formatted_data, "{line}").expect("Writing to String cannot fail");
+            *last_line_done = line.ends_with('\n');
+        }
+        Ok(formatted_data)
+    }
+
+    fn process_defmt(
+        buffer: &[u8],
+        defmt_state: Option<&DefmtState>,
+        formatter: &Formatter,
+        cwd: &Path,
+    ) -> Result<String> {
+        let Some(DefmtState { table, locs }) = defmt_state else {
+            return Ok(String::from(
+                "Trying to process defmt data but table or locations could not be loaded.\n",
+            ));
+        };
+
+        let mut stream_decoder = table.new_stream_decoder();
+
+        // FIXME: this assumes we read frames atomically which is implementation-defined and we
+        // should be able to handle the case where a frame is split across two reads with a
+        // temporary buffer.
+        stream_decoder.received(buffer);
+
+        let mut formatted_data = String::new();
+        loop {
+            match stream_decoder.decode() {
+                Ok(frame) => {
+                    let loc = locs.as_ref().and_then(|locs| locs.get(&frame.index()));
+                    let (file, line, module) = if let Some(loc) = loc {
+                        let relpath = loc.file.strip_prefix(cwd).unwrap_or(&loc.file);
+                        (
+                            relpath.display().to_string(),
+                            Some(loc.line.try_into().unwrap()),
+                            Some(loc.module.as_str()),
+                        )
+                    } else {
+                        (
+                            format!(
+                                "└─ <invalid location: defmt frame-index: {}>",
+                                frame.index()
+                            ),
+                            None,
+                            None,
+                        )
+                    };
+                    let s = formatter.format_frame(frame, Some(&file), line, module);
+                    writeln!(formatted_data, "{s}").expect("Writing to String cannot fail");
+                }
+                Err(DecodeError::UnexpectedEof) => break,
+                Err(DecodeError::Malformed) if table.encoding().can_recover() => {
+                    // If recovery is possible, skip the current frame and continue with new data.
+                }
+                Err(DecodeError::Malformed) => {
+                    return Err(anyhow!(
+                        "Unrecoverable error while decoding Defmt \
+                        data and some data may have been lost: {:?}",
+                        DecodeError::Malformed
+                    ));
+                }
+            }
+        }
+
+        Ok(formatted_data)
+    }
+}
+
 pub trait ChannelDataCallbacks {
     fn on_binary_data(&mut self, channel: usize, data: &[u8]) -> Result<()> {
         let mut formatted_data = String::with_capacity(data.len() * 4);
@@ -212,7 +340,7 @@ pub trait ChannelDataCallbacks {
 pub struct RttActiveUpChannel {
     pub up_channel: UpChannel,
     pub channel_name: String,
-    pub data_format: ChannelDataConfig,
+    pub data_format: ChannelDataFormat,
     rtt_buffer: RttBuffer,
 }
 
@@ -228,12 +356,12 @@ impl RttActiveUpChannel {
         let is_defmt_channel = up_channel.name() == Some("defmt");
 
         let data_format = match channel_config.data_format {
-            DataFormat::String if !is_defmt_channel => ChannelDataConfig::String {
+            DataFormat::String if !is_defmt_channel => ChannelDataFormat::String {
                 timestamp_offset: channel_config.show_timestamps.then_some(timestamp_offset),
                 last_line_done: true,
             },
 
-            DataFormat::BinaryLE if !is_defmt_channel => ChannelDataConfig::BinaryLE,
+            DataFormat::BinaryLE if !is_defmt_channel => ChannelDataFormat::BinaryLE,
 
             // either DataFormat::Defmt is configured, or defmt_enabled is true
             _ => {
@@ -260,11 +388,12 @@ impl RttActiveUpChannel {
                     }
                 };
 
-                ChannelDataConfig::Defmt {
+                ChannelDataFormat::Defmt {
                     formatter: Formatter::new(FormatterConfig {
                         format,
                         is_timestamp_available: has_timestamp,
                     }),
+                    cwd: std::env::current_dir().unwrap(),
                 }
             }
         };
@@ -283,7 +412,7 @@ impl RttActiveUpChannel {
 
         if let Some(mode) = channel_config.mode.or(
             // Try not to corrupt the byte stream if using defmt
-            if matches!(data_format, ChannelDataConfig::Defmt { .. }) {
+            if matches!(data_format, ChannelDataFormat::Defmt { .. }) {
                 Some(ChannelMode::BlockIfFull)
             } else {
                 None
@@ -340,114 +469,8 @@ impl RttActiveUpChannel {
 
         let buffer = &self.rtt_buffer.0[..bytes_read];
 
-        match self.data_format {
-            ChannelDataConfig::BinaryLE => collector.on_binary_data(self.number(), buffer),
-            ChannelDataConfig::String {
-                timestamp_offset,
-                ref mut last_line_done,
-            } => {
-                let string = Self::process_string(buffer, timestamp_offset, last_line_done)?;
-                collector.on_string_data(self.number(), string)
-            }
-            ChannelDataConfig::Defmt { ref formatter } => {
-                let string = self.process_defmt(buffer, defmt_state, formatter)?;
-                collector.on_string_data(self.number(), string)
-            }
-        }
-    }
-
-    fn process_string(
-        buffer: &[u8],
-        offset: Option<UtcOffset>,
-        last_line_done: &mut bool,
-    ) -> Result<String> {
-        let incoming = String::from_utf8_lossy(buffer);
-
-        let Some(offset) = offset else {
-            return Ok(incoming.to_string());
-        };
-
-        let timestamp = OffsetDateTime::now_utc()
-            .to_offset(offset)
-            .format(format_description!(
-                "[hour repr:24]:[minute]:[second].[subsecond digits:3]"
-            ))?;
-
-        let mut formatted_data = String::new();
-        for line in incoming.split_inclusive('\n') {
-            if *last_line_done {
-                write!(formatted_data, "{timestamp}: ").expect("Writing to String cannot fail");
-            }
-            write!(formatted_data, "{line}").expect("Writing to String cannot fail");
-            *last_line_done = line.ends_with('\n');
-        }
-        Ok(formatted_data)
-    }
-
-    fn process_defmt(
-        &self,
-        buffer: &[u8],
-        defmt_state: Option<&DefmtState>,
-        formatter: &Formatter,
-    ) -> Result<String> {
-        let Some(DefmtState { table, locs }) = defmt_state else {
-            return Ok(String::from(
-                "Trying to process defmt data but table or locations could not be loaded.\n",
-            ));
-        };
-
-        let mut stream_decoder = table.new_stream_decoder();
-        stream_decoder.received(buffer);
-        let current_dir = std::env::current_dir().unwrap();
-
-        let mut formatted_data = String::new();
-        loop {
-            match stream_decoder.decode() {
-                Ok(frame) => {
-                    let loc = locs.as_ref().and_then(|locs| locs.get(&frame.index()));
-                    let (file, line, module) = if let Some(loc) = loc {
-                        let relpath = loc.file.strip_prefix(&current_dir).unwrap_or(&loc.file);
-                        (
-                            relpath.display().to_string(),
-                            Some(loc.line.try_into().unwrap()),
-                            Some(loc.module.as_str()),
-                        )
-                    } else {
-                        (
-                            format!(
-                                "└─ <invalid location: defmt frame-index: {}>",
-                                frame.index()
-                            ),
-                            None,
-                            None,
-                        )
-                    };
-                    let s = formatter.format_frame(frame, Some(&file), line, module);
-                    writeln!(formatted_data, "{s}").expect("Writing to String cannot fail");
-                }
-                Err(DecodeError::UnexpectedEof) => break,
-                Err(DecodeError::Malformed) if table.encoding().can_recover() => {
-                    // If recovery is possible, skip the current frame and continue with new data.
-                }
-                Err(DecodeError::Malformed) => {
-                    return Err(anyhow!(
-                        "Unrecoverable error while decoding Defmt \
-                        data and some data may have been lost: {:?}",
-                        DecodeError::Malformed
-                    ));
-                }
-            }
-        }
-
-        Ok(formatted_data)
-    }
-
-    pub(crate) fn set_mode(
-        &self,
-        core: &mut Core<'_>,
-        block_if_full: ChannelMode,
-    ) -> Result<(), Error> {
-        self.up_channel.set_mode(core, block_if_full)
+        self.data_format
+            .process(self.number(), buffer, defmt_state, collector)
     }
 }
 
@@ -495,17 +518,10 @@ pub struct DefmtState {
     pub locs: Option<defmt_decoder::Locations>,
 }
 impl DefmtState {
-    pub fn try_from_elf(elf: &Path) -> Result<Option<Self>> {
-        let elf = fs::read(elf).map_err(|err| {
-            anyhow!(
-                "Error reading program binary while initalizing RTT: {}",
-                err
-            )
-        })?;
-
-        if let Some(table) = defmt_decoder::Table::parse(&elf)? {
+    pub fn try_from_bytes(buffer: &[u8]) -> Result<Option<Self>> {
+        if let Some(table) = defmt_decoder::Table::parse(buffer)? {
             let locs = {
-                let locs = table.get_locations(&elf)?;
+                let locs = table.get_locations(buffer)?;
 
                 if !table.is_empty() && locs.is_empty() {
                     tracing::warn!("Insufficient DWARF info; compile your program with `debug = 2` to enable location info.");
@@ -537,12 +553,10 @@ impl RttActiveTarget {
     pub fn new(
         core: &mut Core,
         rtt: probe_rs::rtt::Rtt,
-        elf_file: &Path,
+        defmt_state: Option<DefmtState>,
         rtt_config: &RttConfig,
         timestamp_offset: UtcOffset,
     ) -> Result<Self> {
-        let defmt_state = DefmtState::try_from_elf(elf_file)?;
-
         let mut active_up_channels = HashMap::new();
         let mut active_down_channels = HashMap::new();
 
@@ -593,12 +607,8 @@ impl RttActiveTarget {
     pub fn get_rtt_symbol<T: Read + Seek>(file: &mut T) -> Option<u64> {
         let mut buffer = Vec::new();
         if file.read_to_end(&mut buffer).is_ok() {
-            if let Ok(binary) = goblin::elf::Elf::parse(buffer.as_slice()) {
-                for sym in &binary.syms {
-                    if binary.strtab.get_at(sym.st_name) == Some("_SEGGER_RTT") {
-                        return Some(sym.st_value);
-                    }
-                }
+            if let Some(rtt) = Self::get_rtt_symbol_from_bytes(buffer.as_slice()) {
+                return Some(rtt);
             }
         }
 
@@ -608,6 +618,18 @@ impl RttActiveTarget {
         None
     }
 
+    pub fn get_rtt_symbol_from_bytes(buffer: &[u8]) -> Option<u64> {
+        if let Ok(binary) = goblin::elf::Elf::parse(buffer) {
+            for sym in &binary.syms {
+                if binary.strtab.get_at(sym.st_name) == Some("_SEGGER_RTT") {
+                    return Some(sym.st_value);
+                }
+            }
+        }
+
+        None
+    }
+
     /// Polls the RTT target on all channels and returns available data.
     /// An error on any channel will return an error instead of incomplete data.
     pub fn poll_rtt_fallible(
@@ -637,3 +659,72 @@ impl fmt::Debug for RttBuffer {
         self.0.fmt(f)
     }
 }
+
+fn try_attach_to_rtt_inner(
+    mut attach: impl FnMut(&[MemoryRegion], &ScanRegion) -> Result<Option<Rtt>>,
+    timeout: Duration,
+    memory_map: &[MemoryRegion],
+    rtt_region: &ScanRegion,
+) -> Result<Option<Rtt>> {
+    let t = Instant::now();
+    let mut rtt_init_attempt = 1;
+    let mut last_error = None;
+    while t.elapsed() < timeout {
+        tracing::debug!("Initializing RTT (attempt {})...", rtt_init_attempt);
+        rtt_init_attempt += 1;
+
+        match attach(memory_map, rtt_region) {
+            Ok(rtt) => return Ok(rtt),
+            Err(e) => last_error = Some(e),
+        }
+
+        tracing::debug!("Failed to initialize RTT. Retrying until timeout.");
+        thread::sleep(Duration::from_millis(10));
+    }
+
+    // Timeout
+    if let Some(err) = last_error {
+        Err(err)
+    } else {
+        Err(anyhow!("Error setting up RTT"))
+    }
+}
+
+// TODO: these should be part of the library, but that requires refactoring the errors to not use
+// anyhow. Also, we probably should only have one variant of this function and pass the closure
+// in as an argument.
+
+/// Try to attach to RTT, with the given timeout.
+pub fn try_attach_to_rtt(
+    core: &mut Core<'_>,
+    timeout: Duration,
+    memory_map: &[MemoryRegion],
+    rtt_region: &ScanRegion,
+) -> Result<Option<Rtt>> {
+    try_attach_to_rtt_inner(
+        |memory_map, rtt_region| attach_to_rtt(core, memory_map, rtt_region),
+        timeout,
+        memory_map,
+        rtt_region,
+    )
+}
+
+/// Try to attach to RTT, with the given timeout.
+pub fn try_attach_to_rtt_shared(
+    session: &parking_lot::FairMutex<Session>,
+    core_id: usize,
+    memory_map: &[MemoryRegion],
+    timeout: Duration,
+    rtt_region: &ScanRegion,
+) -> Result<Option<Rtt>> {
+    try_attach_to_rtt_inner(
+        |memory_map, rtt_region| {
+            let mut session_handle = session.lock();
+            let mut core = session_handle.core(core_id)?;
+            attach_to_rtt(&mut core, memory_map, rtt_region)
+        },
+        timeout,
+        memory_map,
+        rtt_region,
+    )
+}
diff --git a/probe-rs/src/config/registry.rs b/probe-rs/src/config/registry.rs
index acef7dfe..1cf7ac0c 100644
--- a/probe-rs/src/config/registry.rs
+++ b/probe-rs/src/config/registry.rs
@@ -12,33 +12,23 @@ static REGISTRY: Lazy<Arc<Mutex<Registry>>> =
 
 /// Error type for all errors which occur when working
 /// with the internal registry of targets.
-#[derive(Debug, thiserror::Error)]
+#[derive(Debug, thiserror::Error, docsplay::Display)]
 pub enum RegistryError {
-    /// The requested chip was not found in the registry.
-    #[error("The requested chip '{0}' was not found in the list of known targets.")]
+    /// The requested chip '{0}' was not found in the list of known targets.
     ChipNotFound(String),
-    /// Multiple chips found which match the given string, unable to return a single chip.
-    #[error("Found multiple chips matching '{0}', unable to select a single chip. ({1})")]
+    /// Found multiple chips matching '{0}', unable to select a single chip. ({1})
     ChipNotUnique(String, String),
-    /// When searching for a chip based on information read from the target,
-    /// no matching chip was found in the registry.
-    #[error("The connected chip could not automatically be determined.")]
+    /// The connected chip could not automatically be determined.
     ChipAutodetectFailed,
-    /// A core type contained in a target description is not supported
-    /// in probe-rs.
-    #[error("The core type '{0}' is not supported in probe-rs.")]
+    /// The core type '{0}' is not supported in probe-rs.
     UnknownCoreType(String),
-    /// An IO error which occurred when trying to read a target description file.
-    #[error("An IO error was encountered")]
+    /// An IO error occurred when trying to read a target description file.
     Io(#[from] std::io::Error),
     /// An error occurred while deserializing a YAML target description file.
-    #[error("Deserializing the yaml encountered an error")]
     Yaml(#[from] serde_yaml::Error),
-    /// An invalid [`ChipFamily`] was encountered.
-    #[error("Invalid chip family definition ({})", .0.name)]
+    /// Invalid chip family definition ({0.name}): {1}
     InvalidChipFamilyDefinition(Box<ChipFamily>, String),
-    /// One of the RTT scan ranges is not enclosed in exactly one RAM region.
-    #[error("Chip's RTT scan region {:#010x}..{:#010x} is not enclosed by any single RAM region.", .0.start, .0.end)]
+    /// Chip's RTT scan region {0:#010X?} is not enclosed by any single RAM region.
     InvalidRttScanRange(std::ops::Range<u64>),
 }
 
@@ -128,27 +118,19 @@ struct Registry {
 }
 
 impl Registry {
-    #[cfg(feature = "builtin-targets")]
     fn from_builtin_families() -> Self {
-        const BUILTIN_TARGETS: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/targets.bincode"));
+        #[cfg(feature = "builtin-targets")]
+        let mut families = {
+            const BUILTIN_TARGETS: &[u8] =
+                include_bytes!(concat!(env!("OUT_DIR"), "/targets.bincode"));
 
-        let mut families: Vec<ChipFamily> = match bincode::deserialize(BUILTIN_TARGETS) {
-            Ok(families) => families,
-            Err(err) => panic!("Failed to deserialize builtin targets. This is a bug : {err:?}"),
+            bincode::deserialize(BUILTIN_TARGETS)
+                .expect("Failed to deserialize builtin targets. This is a bug")
         };
 
-        add_generic_targets(&mut families);
-
-        // We skip validating the targets here as this is done at a later stage in `get_target`.
-        // Additionally, validation for existing targets is done in the tests `validate_generic_targets` and
-        // `validate_builtin` as well, to ensure we do not ship broken target definitions.
-
-        Self { families }
-    }
-
-    #[cfg(not(feature = "builtin-targets"))]
-    fn from_builtin_families() -> Self {
+        #[cfg(not(feature = "builtin-targets"))]
         let mut families = vec![];
+
         add_generic_targets(&mut families);
 
         // We skip validating the targets here as this is done at a later stage in `get_target`.
@@ -163,112 +145,110 @@ impl Registry {
     }
 
     fn get_target_by_name(&self, name: impl AsRef<str>) -> Result<Target, RegistryError> {
-        let (target, _) = self.get_target_and_family_by_name(name)?;
+        let (target, _) = self.get_target_and_family_by_name(name.as_ref())?;
         Ok(target)
     }
 
     fn get_target_and_family_by_name(
         &self,
-        name: impl AsRef<str>,
+        name: &str,
     ) -> Result<(Target, ChipFamily), RegistryError> {
-        let name = name.as_ref();
-
         tracing::debug!("Searching registry for chip with name {}", name);
 
-        let (family, chip) = {
-            // Try get the corresponding chip.
-            let mut selected_family_and_chip = None;
-            let mut exact_matches = 0;
-            let mut partial_matches = Vec::new();
-            for family in &self.families {
-                for variant in family.variants.iter() {
-                    if match_name_prefix(&variant.name, name) {
-                        if variant.name.len() == name.len() {
-                            tracing::debug!("Exact match for chip name: {}", variant.name);
-                            exact_matches += 1;
-                        } else {
-                            tracing::debug!("Partial match for chip name: {}", &variant.name);
-                            partial_matches.push(variant.name.clone());
-                            if exact_matches > 0 {
-                                continue;
-                            }
+        // Try get the corresponding chip.
+        let mut selected_family_and_chip = None;
+        let mut exact_matches = 0;
+        let mut partial_matches = Vec::new();
+        for family in self.families.iter() {
+            for variant in family.variants.iter() {
+                if match_name_prefix(&variant.name, name) {
+                    if variant.name.len() == name.len() {
+                        tracing::debug!("Exact match for chip name: {}", variant.name);
+                        exact_matches += 1;
+                    } else {
+                        tracing::debug!("Partial match for chip name: {}", variant.name);
+                        partial_matches.push(variant.name.as_str());
+                        // Only select partial match if we don't have an exact match yet
+                        if exact_matches > 0 {
+                            continue;
                         }
-                        selected_family_and_chip = Some((family, variant));
                     }
+                    selected_family_and_chip = Some((family, variant));
                 }
             }
-            if exact_matches == 0 && partial_matches.len() > 1 {
-                tracing::warn!(
-                    "Ignoring ambiguous matches for specified chip name {}",
-                    name,
-                );
-                let mut suggestions;
-                if partial_matches.len() <= 100 {
-                    suggestions = partial_matches.join(", ");
-                } else {
-                    // prevent too much text being printed if too many matches
-                    suggestions = partial_matches[0..100].join(", ");
-                    suggestions.push_str(&format!(" and {} more", partial_matches.len() - 100))
+        }
+
+        let Some((family, chip)) = selected_family_and_chip else {
+            return Err(RegistryError::ChipNotFound(name.to_string()));
+        };
+
+        if exact_matches == 0 {
+            match partial_matches.len() {
+                0 => {}
+                1 => {
+                    tracing::warn!(
+                        "Found chip {} which matches given partial name {}. Consider specifying its full name.",
+                        chip.name,
+                        name,
+                    );
+                }
+                matches => {
+                    const MAX_PRINTED_MATCHES: usize = 100;
+                    tracing::warn!(
+                        "Ignoring {matches} ambiguous matches for specified chip name {name}"
+                    );
+
+                    let (print, overflow) =
+                        partial_matches.split_at(MAX_PRINTED_MATCHES.min(matches));
+
+                    let mut suggestions = print.join(", ");
+
+                    // Avoid "and 1 more" by printing the last item.
+                    match overflow.len() {
+                        0 => {}
+                        1 => suggestions.push_str(&format!(", {}", overflow[0])),
+                        _ => suggestions.push_str(&format!("and {} more", overflow.len())),
+                    }
+
+                    return Err(RegistryError::ChipNotUnique(name.to_string(), suggestions));
                 }
-                return Err(RegistryError::ChipNotUnique(name.to_owned(), suggestions));
-            }
-            let (family, chip) = selected_family_and_chip
-                .ok_or_else(|| RegistryError::ChipNotFound(name.to_owned()))?;
-            if exact_matches == 0 && partial_matches.len() == 1 {
-                tracing::warn!(
-                    "Found chip {} which matches given partial name {}. Consider specifying its full name.",
-                    chip.name,
-                    name,
-                );
-            }
-            if chip.name.to_ascii_lowercase() != name.to_ascii_lowercase() {
-                tracing::warn!(
-                    "Matching {} based on wildcard. Consider specifying the chip as {} instead.",
-                    name,
-                    chip.name,
-                );
             }
+        }
+
+        if !chip.name.eq_ignore_ascii_case(name) {
+            tracing::warn!(
+                "Matching {} based on wildcard. Consider specifying the chip as {} instead.",
+                name,
+                chip.name,
+            );
+        }
 
-            // Try get the correspnding flash algorithm.
-            (family, chip)
-        };
         let targ = self.get_target(family, chip)?;
         Ok((targ, family.clone()))
     }
 
-    fn get_targets_by_family_name(
-        &self,
-        family_name: impl AsRef<str>,
-    ) -> Result<Vec<String>, RegistryError> {
-        let name: &str = family_name.as_ref();
-
-        let family = {
-            let mut finded_family = None;
-            let mut exact_matches = 0;
-            for family in &self.families {
-                if match_name_prefix(&family.name, name) {
-                    if family.name.len() == name.len() {
-                        tracing::debug!("Exact match for family name: {}", family.name);
-                        exact_matches += 1;
-                    } else {
-                        tracing::debug!("Partial match for family name: {}", family.name);
-                        if exact_matches > 0 {
-                            continue;
-                        }
+    fn get_targets_by_family_name(&self, name: &str) -> Result<Vec<String>, RegistryError> {
+        let mut found_family = None;
+        let mut exact_matches = 0;
+        for family in self.families.iter() {
+            if match_name_prefix(&family.name, name) {
+                if family.name.len() == name.len() {
+                    tracing::debug!("Exact match for family name: {}", family.name);
+                    exact_matches += 1;
+                } else {
+                    tracing::debug!("Partial match for family name: {}", family.name);
+                    if exact_matches > 0 {
+                        continue;
                     }
-                    finded_family = Some(family);
                 }
+                found_family = Some(family);
             }
-            finded_family.ok_or_else(|| RegistryError::ChipNotFound(name.to_owned()))?
-        };
-
-        let mut all_family_targets = Vec::new();
-
-        for target in &family.variants {
-            all_family_targets.push(target.name.clone());
         }
+        let Some(family) = found_family else {
+            return Err(RegistryError::ChipNotFound(name.to_string()));
+        };
 
-        Ok(all_family_targets)
+        Ok(family.variants.iter().map(|v| v.name.to_string()).collect())
     }
 
     fn search_chips(&self, name: &str) -> Vec<String> {
@@ -278,12 +258,8 @@ impl Registry {
 
         for family in &self.families {
             for variant in family.variants.iter() {
-                if variant
-                    .name
-                    .to_ascii_lowercase()
-                    .starts_with(&name.to_ascii_lowercase())
-                {
-                    targets.push(variant.name.to_string())
+                if match_name_prefix(name, &variant.name) {
+                    targets.push(variant.name.to_string());
                 }
             }
         }
@@ -346,13 +322,9 @@ impl Registry {
             .validate()
             .map_err(|e| RegistryError::InvalidChipFamilyDefinition(Box::new(family.clone()), e))?;
 
-        let index = self
-            .families
-            .iter()
-            .position(|old_family| old_family.name == family.name);
-        if let Some(index) = index {
-            self.families.remove(index);
-        }
+        self.families
+            .retain(|old_family| !old_family.name.eq_ignore_ascii_case(&family.name));
+
         self.families.push(family);
 
         Ok(())
@@ -368,7 +340,10 @@ pub fn get_target_by_name(name: impl AsRef<str>) -> Result<Target, RegistryError
 pub fn get_target_and_family_by_name(
     name: impl AsRef<str>,
 ) -> Result<(Target, ChipFamily), RegistryError> {
-    REGISTRY.lock().unwrap().get_target_and_family_by_name(name)
+    REGISTRY
+        .lock()
+        .unwrap()
+        .get_target_and_family_by_name(name.as_ref())
 }
 
 /// Get all target from the internal registry based on its family name.
@@ -378,10 +353,10 @@ pub fn get_targets_by_family_name(
     REGISTRY
         .lock()
         .unwrap()
-        .get_targets_by_family_name(family_name)
+        .get_targets_by_family_name(family_name.as_ref())
 }
 
-/// Get a target from the internal registry based on its name.
+/// Returns targets from the internal registry that match the given name.
 pub fn search_chips(name: impl AsRef<str>) -> Result<Vec<String>, RegistryError> {
     Ok(REGISTRY.lock().unwrap().search_chips(name.as_ref()))
 }
@@ -434,8 +409,8 @@ pub fn families() -> Result<Vec<ChipFamily>, RegistryError> {
 fn match_name_prefix(pattern: &str, name: &str) -> bool {
     // If `name` is shorter than `pattern` but all characters in `name` match,
     // the iterator will end early and the function returns true.
-    for (n, p) in name.to_ascii_lowercase().chars().zip(pattern.chars()) {
-        if p.to_ascii_lowercase() != n && p != 'x' {
+    for (n, p) in name.chars().zip(pattern.chars()) {
+        if !n.eq_ignore_ascii_case(&p) && p != 'x' {
             return false;
         }
     }
diff --git a/probe-rs/src/config/target.rs b/probe-rs/src/config/target.rs
index 636721b7..c1a6aa0f 100644
--- a/probe-rs/src/config/target.rs
+++ b/probe-rs/src/config/target.rs
@@ -85,7 +85,7 @@ impl Target {
     /// Create a new target for the given details.
     ///
     /// We suggest never using this function directly.
-    /// Use (crate::registry::Registry::get_target)[`Registry::get_target`] instead.
+    /// Use [`crate::config::registry::get_target_by_name`] instead.
     /// This will ensure that the used target is valid.
     ///
     /// The user has to make sure that all the cores have the same [`Architecture`].
diff --git a/probe-rs/src/debug/debug_info.rs b/probe-rs/src/debug/debug_info.rs
index c112665c..cad79e8a 100644
--- a/probe-rs/src/debug/debug_info.rs
+++ b/probe-rs/src/debug/debug_info.rs
@@ -25,6 +25,8 @@ use std::{
 use typed_path::{TypedPath, TypedPathBuf};
 
 pub(crate) type GimliReader = gimli::EndianReader<gimli::LittleEndian, std::rc::Rc<[u8]>>;
+pub(crate) type GimliReaderOffset =
+    <gimli::EndianReader<gimli::LittleEndian, Rc<[u8]>> as gimli::Reader>::Offset;
 
 pub(crate) type GimliAttribute = gimli::Attribute<GimliReader>;
 
@@ -338,7 +340,7 @@ impl DebugInfo {
         &self,
         memory: &mut impl MemoryInterface,
         address: u64,
-        unwind_context: &mut UnwindContext<DwarfReader>,
+        unwind_context: &mut UnwindContext<GimliReaderOffset>,
         unwind_registers: &registers::DebugRegisters,
     ) -> Result<Vec<StackFrame>, DebugError> {
         // When reporting the address, we format it as a hex string, with the width matching
@@ -1000,10 +1002,10 @@ pub(crate) fn canonical_path_eq(
 
 /// Get a handle to the [`gimli::UnwindTableRow`] for this call frame, so that we can reference it to unwind register values.
 fn get_unwind_info<'a>(
-    unwind_context: &'a mut UnwindContext<DwarfReader>,
-    frame_section: &'a DebugFrame<DwarfReader>,
+    unwind_context: &'a mut UnwindContext<GimliReaderOffset>,
+    frame_section: &DebugFrame<DwarfReader>,
     frame_program_counter: u64,
-) -> Result<&'a gimli::UnwindTableRow<DwarfReader, gimli::StoreOnHeap>, DebugError> {
+) -> Result<&'a gimli::UnwindTableRow<GimliReaderOffset>, DebugError> {
     let transform_error = |error| {
         DebugError::Other(anyhow::anyhow!(
             "UNWIND: Error reading FrameDescriptorEntry at PC={} : {}",
@@ -1033,7 +1035,7 @@ fn get_unwind_info<'a>(
 }
 
 /// Determines the CFA (canonical frame address) for the current [`gimli::UnwindTableRow`], using the current register values.
-fn determine_cfa<R: gimli::Reader>(
+fn determine_cfa<R: gimli::ReaderOffset>(
     unwind_registers: &DebugRegisters,
     unwind_info: &UnwindTableRow<R>,
 ) -> Result<Option<u64>, crate::Error> {
@@ -1083,7 +1085,7 @@ fn unwind_register(
     debug_register: &mut super::DebugRegister,
     // The callee_frame_registers are used to lookup values and never updated.
     callee_frame_registers: &DebugRegisters,
-    unwind_info: Option<&gimli::UnwindTableRow<DwarfReader, gimli::StoreOnHeap>>,
+    unwind_info: Option<&gimli::UnwindTableRow<GimliReaderOffset>>,
     unwind_cfa: Option<u64>,
     unwound_return_address: &mut Option<RegisterValue>,
     memory: &mut dyn MemoryInterface,
diff --git a/probe-rs/src/flashing/erase.rs b/probe-rs/src/flashing/erase.rs
index 1e9a8a84..1df48f94 100644
--- a/probe-rs/src/flashing/erase.rs
+++ b/probe-rs/src/flashing/erase.rs
@@ -19,17 +19,12 @@ pub fn erase_all(session: &mut Session, progress: Option<FlashProgress>) -> Resu
     for region in &session.target().memory_map {
         if let MemoryRegion::Nvm(region) = region {
             if region.is_alias {
-                tracing::debug!(
-                    "Skipping alias memory region {:#010X}..{:#010X}",
-                    region.range.start,
-                    region.range.end
-                );
+                tracing::debug!("Skipping alias memory region {:#010X?}", region.range);
                 continue;
             }
             tracing::debug!(
-                "    region: {:#010X}..{:#010X} ({} bytes)",
-                region.range.start,
-                region.range.end,
+                "    region: {:#010X?} ({} bytes)",
+                region.range,
                 region.range.end - region.range.start
             );
 
@@ -113,17 +108,12 @@ pub fn erase_sectors(
     for region in &session.target().memory_map {
         if let MemoryRegion::Nvm(region) = region {
             if region.is_alias {
-                tracing::debug!(
-                    "Skipping alias memory region {:#010X}..{:#010X}",
-                    region.range.start,
-                    region.range.end
-                );
+                tracing::debug!("Skipping alias memory region {:#010X?}", region.range);
                 continue;
             }
             tracing::debug!(
-                "    region: {:08x}-{:08x} ({} bytes)",
-                region.range.start,
-                region.range.end,
+                "    region: {:#010X?} ({} bytes)",
+                region.range,
                 region.range.end - region.range.start
             );
 
diff --git a/probe-rs/src/flashing/error.rs b/probe-rs/src/flashing/error.rs
index 3313d7d1..f746fe17 100644
--- a/probe-rs/src/flashing/error.rs
+++ b/probe-rs/src/flashing/error.rs
@@ -6,14 +6,10 @@ use std::ops::Range;
 #[derive(thiserror::Error, Debug)]
 pub enum FlashError {
     /// No flash memory contains the entire requested memory range.
-    #[error(
-        "No flash memory contains the entire requested memory range {start:#010x}..{end:#010x}."
-    )]
+    #[error("No flash memory contains the entire requested memory range {range:#010X?}.")]
     NoSuitableNvm {
-        /// The start of the requested memory range.
-        start: u64,
-        /// The end of the requested memory range.
-        end: u64,
+        /// The requested memory range.
+        range: Range<u64>,
         /// The source of this target description (was it a built in target or one loaded externally and from what file path?).
         description_source: TargetDescriptionSource,
     },
@@ -103,7 +99,7 @@ pub enum FlashError {
     // TODO: 1 Add information about flash (name, address)
     // TODO: 2 Add source of target definition (built-in, yaml)
     /// No flash algorithm was linked to this target.
-    #[error("Trying to write to flash region {:#010X}..{:#010X}, but no suitable (default) flash loader algorithm is linked to the given target: {name}.", .range.start, .range.end)]
+    #[error("Trying to write to flash region {range:#010X?}, but no suitable (default) flash loader algorithm is linked to the given target: {name}.")]
     NoFlashLoaderAlgorithmAttached {
         /// The name of the chip.
         name: String,
diff --git a/probe-rs/src/flashing/flasher.rs b/probe-rs/src/flashing/flasher.rs
index e12c36d4..2f09423d 100644
--- a/probe-rs/src/flashing/flasher.rs
+++ b/probe-rs/src/flashing/flasher.rs
@@ -204,7 +204,6 @@ impl<'session> Flasher<'session> {
         &mut self,
         clock: Option<u32>,
     ) -> Result<ActiveFlasher<'_, O>, FlashError> {
-        #[cfg(feature = "rtt")]
         let memory_map = self.session.target().memory_map.clone();
         // Attach to memory and core.
         let core = self
@@ -215,9 +214,7 @@ impl<'session> Flasher<'session> {
         tracing::debug!("Preparing Flasher for operation {}", O::operation_name());
         let mut flasher = ActiveFlasher::<O> {
             core,
-            #[cfg(feature = "rtt")]
             rtt: None,
-            #[cfg(feature = "rtt")]
             memory_map,
             progress: self.progress.clone(),
             flash_algorithm: self.flash_algorithm.clone(),
@@ -563,9 +560,7 @@ fn into_reg(val: u64) -> Result<u32, FlashError> {
 
 pub(super) struct ActiveFlasher<'probe, O: Operation> {
     core: Core<'probe>,
-    #[cfg(feature = "rtt")]
     rtt: Option<crate::rtt::Rtt>,
-    #[cfg(feature = "rtt")]
     memory_map: Vec<MemoryRegion>,
     progress: FlashProgress,
     flash_algorithm: FlashAlgorithm,
@@ -714,8 +709,8 @@ impl<'probe, O: Operation> ActiveFlasher<'probe, O> {
         // Resume target operation.
         self.core.run()?;
 
-        #[cfg(feature = "rtt")]
         if let Some(rtt_address) = self.flash_algorithm.rtt_control_block {
+            // FIXME: replace this with try_attach_to_rtt once it's been moved to the library
             let now = Instant::now();
             let mut last_error = None;
             while self.rtt.is_none() {
@@ -760,7 +755,6 @@ impl<'probe, O: Operation> ActiveFlasher<'probe, O> {
                     timeout_ocurred = false;
                     // Once the core is halted we know for sure all RTT data is written
                     // so we can read all of it.
-                    #[cfg(feature = "rtt")]
                     self.read_rtt()?;
                     break;
                 }
@@ -775,7 +769,6 @@ impl<'probe, O: Operation> ActiveFlasher<'probe, O> {
             }
 
             // Periodically read RTT.
-            #[cfg(feature = "rtt")]
             self.read_rtt()?;
 
             std::thread::sleep(Duration::from_millis(1));
@@ -789,7 +782,6 @@ impl<'probe, O: Operation> ActiveFlasher<'probe, O> {
         Ok(r)
     }
 
-    #[cfg(feature = "rtt")]
     fn read_rtt(&mut self) -> Result<(), FlashError> {
         if let Some(rtt) = &mut self.rtt {
             for channel in rtt.up_channels().iter() {
diff --git a/probe-rs/src/flashing/loader.rs b/probe-rs/src/flashing/loader.rs
index 41beab4c..0a6d04b7 100644
--- a/probe-rs/src/flashing/loader.rs
+++ b/probe-rs/src/flashing/loader.rs
@@ -56,8 +56,7 @@ impl FlashLoader {
                 Some(MemoryRegion::Ram(region)) => address = region.range.end,
                 _ => {
                     return Err(FlashError::NoSuitableNvm {
-                        start: range.start,
-                        end: range.end,
+                        range,
                         description_source: self.source.clone(),
                     })
                 }
@@ -386,17 +385,12 @@ impl FlashLoader {
             .filter_map(MemoryRegion::as_nvm_region)
         {
             if region.is_alias {
-                tracing::debug!(
-                    "Skipping alias memory region {:#010X}..{:#010X}",
-                    region.range.start,
-                    region.range.end
-                );
+                tracing::debug!("Skipping alias memory region {:#010X?}", region.range);
                 continue;
             }
             tracing::debug!(
-                "    region: {:#010X}..{:#010X} ({} bytes)",
-                region.range.start,
-                region.range.end,
+                "    region: {:#010X?} ({} bytes)",
+                region.range,
                 region.range.end - region.range.start
             );
 
@@ -474,9 +468,8 @@ impl FlashLoader {
 
             for region in regions {
                 tracing::debug!(
-                    "    programming region: {:#010X}..{:#010X} ({} bytes)",
-                    region.range.start,
-                    region.range.end,
+                    "    programming region: {:#010X?} ({} bytes)",
+                    region.range,
                     region.range.end - region.range.start
                 );
 
@@ -500,9 +493,8 @@ impl FlashLoader {
             .filter_map(MemoryRegion::as_ram_region)
         {
             tracing::debug!(
-                "    region: {:#010X}..{:#010X} ({} bytes)",
-                region.range.start,
-                region.range.end,
+                "    region: {:#010X?} ({} bytes)",
+                region.range,
                 region.range.end - region.range.start
             );
 
diff --git a/probe-rs/src/flashing/progress.rs b/probe-rs/src/flashing/progress.rs
index b97cd8e1..30ae4355 100644
--- a/probe-rs/src/flashing/progress.rs
+++ b/probe-rs/src/flashing/progress.rs
@@ -97,7 +97,6 @@ impl FlashProgress {
         self.emit(ProgressEvent::FinishedFilling);
     }
 
-    #[cfg(feature = "rtt")]
     pub(super) fn message(&self, message: String) {
         self.emit(ProgressEvent::DiagnosticMessage { message });
     }
diff --git a/probe-rs/src/lib.rs b/probe-rs/src/lib.rs
index 207fccd1..68d3e896 100644
--- a/probe-rs/src/lib.rs
+++ b/probe-rs/src/lib.rs
@@ -83,7 +83,6 @@ pub mod gdb_server;
 pub mod integration;
 mod memory;
 pub mod probe;
-#[cfg(feature = "rtt")]
 pub mod rtt;
 mod semihosting;
 mod session;
diff --git a/probe-rs/src/probe.rs b/probe-rs/src/probe.rs
index 5fa7b158..c3bf1954 100644
--- a/probe-rs/src/probe.rs
+++ b/probe-rs/src/probe.rs
@@ -492,6 +492,11 @@ impl Probe {
     pub fn get_target_voltage(&mut self) -> Result<Option<f32>, DebugProbeError> {
         self.inner.get_target_voltage()
     }
+
+    /// Try to get a J-Link interface from the debug probe.
+    pub fn try_into_jlink(&mut self) -> Result<&mut jlink::JLink, DebugProbeError> {
+        self.inner.try_into_jlink()
+    }
 }
 
 /// An abstraction over a probe driver type.
@@ -668,6 +673,13 @@ pub trait DebugProbe: Send + fmt::Debug {
     fn get_target_voltage(&mut self) -> Result<Option<f32>, DebugProbeError> {
         Ok(None)
     }
+
+    /// Try to get a J-Link interface from the debug probe.
+    fn try_into_jlink(&mut self) -> Result<&mut jlink::JLink, DebugProbeError> {
+        Err(DebugProbeError::Other(anyhow::anyhow!(
+            "This probe does not support J-Link functionality."
+        )))
+    }
 }
 
 impl PartialEq for dyn ProbeFactory {
diff --git a/probe-rs/src/probe/jlink/error.rs b/probe-rs/src/probe/jlink/error.rs
index 22823a64..cb753b1e 100644
--- a/probe-rs/src/probe/jlink/error.rs
+++ b/probe-rs/src/probe/jlink/error.rs
@@ -22,7 +22,7 @@ pub enum JlinkError {
     /// advertised as optional *capability* bits. This error occurs when the capability bit for an
     /// operation isn't set when that operation is attempted.
     ///
-    /// Capabilities can be read by calling [`JayLink::capabilities`], which returns a
+    /// Capabilities can be read by calling [`JLink::capabilities`], which returns a
     /// [`Capabilities`] bitflags struct.
     MissingCapability(Capability),
 
diff --git a/probe-rs/src/probe/jlink/interface.rs b/probe-rs/src/probe/jlink/interface.rs
index 89804978..3d2b3462 100644
--- a/probe-rs/src/probe/jlink/interface.rs
+++ b/probe-rs/src/probe/jlink/interface.rs
@@ -19,10 +19,10 @@ enum_and_set!(
         Bdm3 = 2,
         /// FINE, a two-wire debugging interface used by Renesas RX MCUs.
         ///
-        /// **Note**: due to a bug, attempting to select FINE with [`JayLink::select_inferface`] will
+        /// **Note**: due to a bug, attempting to select FINE with [`JLink::select_inferface`] will
         /// currently hang the probe.
         ///
-        /// [`JayLink::select_inferface`]: crate::JayLink::select_interface
+        /// [`JLink::select_inferface`]: crate::JLink::select_interface
         // FIXME: There's a curious bug that hangs the probe when selecting the FINE interface.
         // Specifically, the probe never sends back the previous interface after it receives the `c7 03`
         // SELECT_IF cmd, even though the normal J-Link software also just sends `c7 03` and gets back
diff --git a/probe-rs/src/probe/jlink/mod.rs b/probe-rs/src/probe/jlink/mod.rs
index 8ad0b211..5334216c 100644
--- a/probe-rs/src/probe/jlink/mod.rs
+++ b/probe-rs/src/probe/jlink/mod.rs
@@ -362,7 +362,7 @@ pub struct JLink {
 
 impl fmt::Debug for JLink {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("JayLink").finish()
+        f.debug_struct("JLink").finish()
     }
 }
 
@@ -537,7 +537,7 @@ impl JLink {
 
     /// Selects the interface to use for talking to the target MCU.
     ///
-    /// Switching interfaces will reset the configured transfer speed, so [`JayLink::set_speed`]
+    /// Switching interfaces will reset the configured transfer speed, so [`JLink::set_speed`]
     /// needs to be called *after* `select_interface`.
     ///
     /// This requires the probe to support [`Capability::SelectIf`].
@@ -775,6 +775,15 @@ impl JLink {
 
         Ok(BitIter::new(&buf[..num_bytes], dir_bit_count).collect())
     }
+
+    /// Enable/Disable the Target Power Supply of the probe.
+    ///
+    /// This is not available on all probes.
+    /// This is avialable on some J-Links
+    pub fn set_kickstart_power(&mut self, enable: bool) -> Result<(), JlinkError> {
+        self.require_capability(Capability::SetKsPower)?;
+        self.write_cmd(&[Command::SetKsPower as u8, if enable { 1 } else { 0 }])
+    }
 }
 
 impl DebugProbe for JLink {
@@ -1011,6 +1020,10 @@ impl DebugProbe for JLink {
     fn has_xtensa_interface(&self) -> bool {
         self.supported_protocols.contains(&WireProtocol::Jtag)
     }
+
+    fn try_into_jlink(&mut self) -> Result<&mut JLink, DebugProbeError> {
+        Ok(self)
+    }
 }
 
 impl RawProtocolIo for JLink {
diff --git a/probe-rs/src/probe/jlink/speed.rs b/probe-rs/src/probe/jlink/speed.rs
index a76d48dd..e716c483 100644
--- a/probe-rs/src/probe/jlink/speed.rs
+++ b/probe-rs/src/probe/jlink/speed.rs
@@ -35,7 +35,7 @@ impl SpeedInfo {
 /// Target communication speed setting.
 ///
 /// This determines the clock frequency of the target communication. Supported speeds for the
-/// currently selected target interface can be fetched via [`JayLink::read_speeds`].
+/// currently selected target interface can be fetched via [`JLink::read_speeds`].
 #[derive(Debug, Copy, Clone)]
 pub struct SpeedConfig {
     raw: u16,
diff --git a/probe-rs/src/rtt.rs b/probe-rs/src/rtt.rs
index 2fa3c634..cd4ce3d0 100644
--- a/probe-rs/src/rtt.rs
+++ b/probe-rs/src/rtt.rs
@@ -265,19 +265,16 @@ impl Rtt {
                     None => return None,
                 };
 
-                let range_len_usize: usize = match range_len.try_into() {
-                    Ok(v) => v,
-                    Err(_) => {
-                        // FIXME: This is not ideal because it means that we
-                        // won't consider a >4GiB region if probe-rs is running
-                        // on a 32-bit host, but it would be relatively unusual
-                        // to use a 32-bit host to debug a 64-bit target.
-                        tracing::warn!("ignoring region of length {} because it is too long to buffer in host memory", range_len);
-                        return None;
-                    }
+                let Ok(range_len) = range_len.try_into() else {
+                    // FIXME: This is not ideal because it means that we
+                    // won't consider a >4GiB region if probe-rs is running
+                    // on a 32-bit host, but it would be relatively unusual
+                    // to use a 32-bit host to debug a 64-bit target.
+                    tracing::warn!("ignoring region of length {} because it is too long to buffer in host memory", range_len);
+                    return None;
                 };
 
-                let mut mem = vec![0; range_len_usize];
+                let mut mem = vec![0; range_len];
                 {
                     core.read(range.start, mem.as_mut()).ok()?;
                 }
@@ -297,17 +294,11 @@ impl Rtt {
             })
             .collect::<Result<Vec<_>, _>>()?;
 
-        if instances.is_empty() {
-            return Err(Error::ControlBlockNotFound);
+        match instances.len() {
+            0 => Err(Error::ControlBlockNotFound),
+            1 => Ok(instances.remove(0)),
+            _ => Err(Error::MultipleControlBlocksFound(instances)),
         }
-
-        if instances.len() > 1 {
-            return Err(Error::MultipleControlBlocksFound(
-                instances.into_iter().map(|i| i.ptr).collect(),
-            ));
-        }
-
-        Ok(instances.remove(0))
     }
 
     /// Returns the memory address of the control block in target memory.
@@ -356,14 +347,14 @@ pub enum ScanRegion {
 #[derive(thiserror::Error, Debug, docsplay::Display)]
 pub enum Error {
     /// RTT control block not found in target memory.
-    /// - Make sure RTT is initialized on the target, AND that there are NO target breakpoints before RTT initalization.
+    /// - Make sure RTT is initialized on the target, AND that there are NO target breakpoints before RTT initialization.
     /// - For VSCode and probe-rs-debugger users, using `halt_after_reset:true` in your `launch.json` file will prevent RTT
     ///   initialization from happening on time.
     /// - Depending on the target, sleep modes can interfere with RTT.
     ControlBlockNotFound,
 
     /// Multiple control blocks found in target memory: {display_list(_0)}.
-    MultipleControlBlocksFound(Vec<u32>),
+    MultipleControlBlocksFound(Vec<Rtt>),
 
     /// The control block has been corrupted. {0}
     ControlBlockCorrupted(String),
@@ -378,21 +369,31 @@ pub enum Error {
     MemoryRead(String),
 }
 
-fn display_list(list: &[u32]) -> String {
+fn display_list(list: &[Rtt]) -> String {
     list.iter()
-        .map(|x| format!("{:#x}", x))
+        .map(|rtt| format!("{:#010X}", rtt.ptr))
         .collect::<Vec<_>>()
         .join(", ")
 }
 
 #[cfg(test)]
 mod test {
+    use super::*;
+
     #[test]
     fn test_how_control_block_list_looks() {
-        let error = super::Error::MultipleControlBlocksFound(vec![0x2000, 0x3000]);
+        fn rtt(ptr: u32) -> Rtt {
+            Rtt {
+                ptr,
+                up_channels: Channels(std::collections::BTreeMap::new()),
+                down_channels: Channels(std::collections::BTreeMap::new()),
+            }
+        }
+
+        let error = Error::MultipleControlBlocksFound(vec![rtt(0x2000), rtt(0x3000)]);
         assert_eq!(
             error.to_string(),
-            "Multiple control blocks found in target memory: 0x2000, 0x3000."
+            "Multiple control blocks found in target memory: 0x00002000, 0x00003000."
         );
     }
 }
diff --git a/probe-rs/targets/LPC55S69.yaml b/probe-rs/targets/LPC55S69.yaml
index 29074ea0..d17aa98a 100644
--- a/probe-rs/targets/LPC55S69.yaml
+++ b/probe-rs/targets/LPC55S69.yaml
@@ -69,7 +69,7 @@ variants:
         cores:
           - cm33_core0
           # - cm33_core1
-      - !Generic
+      - !Nvm
         name: PROGRAM_FLASH_alias
         range:
           start: 0x10000000
@@ -184,7 +184,7 @@ variants:
         cores:
           - cm33_core0
           # - cm33_core1
-      - !Generic
+      - !Nvm
         name: PROGRAM_FLASH_alias
         range:
           start: 0x10000000
@@ -299,7 +299,7 @@ variants:
         cores:
           - cm33_core0
           # - cm33_core1
-      - !Generic
+      - !Nvm
         name: PROGRAM_FLASH_alias
         range:
           start: 0x10000000
diff --git a/probe-rs/targets/STM32U0_Series.yaml b/probe-rs/targets/STM32U0_Series.yaml
new file mode 100644
index 00000000..8281f2dc
--- /dev/null
+++ b/probe-rs/targets/STM32U0_Series.yaml
@@ -0,0 +1,1651 @@
+name: STM32U0 Series
+generated_from_pack: true
+pack_file_release: 1.0.0
+variants:
+- name: STM32U031C6Tx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8008000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_32k
+- name: STM32U031C6Ux
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8008000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_32k
+- name: STM32U031C8Tx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U031C8Ux
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U031F4Px
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8004000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_16k
+- name: STM32U031F6Px
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8008000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_32k
+- name: STM32U031F8Px
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U031G6YxT
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8008000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_32k
+- name: STM32U031G8YxT
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U031K4Ux
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8004000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_16k
+- name: STM32U031K6Ux
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8008000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_32k
+- name: STM32U031K8Ux
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U031R6Ix
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8008000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_32k
+- name: STM32U031R6Tx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8008000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_32k
+- name: STM32U031R8Ix
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U031R8Tx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20002000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20002000
+      end: 0x20003000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073C8Tx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073C8Ux
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073CBTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073CBUx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073CCTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U073CCUx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U073H8YxT
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073HBYxT
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073HCYxT
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U073K8Ux
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073KBUx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073KCUx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U073M8Ix
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073M8Tx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073MBIx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073MBTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073MCIx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U073MCTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U073R8Ix
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073R8Tx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8010000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_64k
+- name: STM32U073RBIx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073RBTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8020000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_128k
+- name: STM32U073RCIx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U073RCTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083CCTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083CCUx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083HCYxT
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083KCUx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083MCIx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083MCTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083RCIx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+- name: STM32U083RCTx
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: 0
+      psel: 0
+  memory_map:
+  - !Ram
+    name: SRAM1
+    range:
+      start: 0x20000000
+      end: 0x20008000
+    cores:
+    - main
+  - !Nvm
+    name: Flash
+    range:
+      start: 0x8000000
+      end: 0x8040000
+    is_boot_memory: true
+    cores:
+    - main
+  - !Generic
+    name: SRAM2
+    range:
+      start: 0x20008000
+      end: 0x2000A000
+    cores:
+    - main
+  flash_algorithms:
+  - stm32u0xx_256k
+flash_algorithms:
+- name: stm32u0xx_32k
+  description: STM32U0xx_32
+  default: true
+  instructions: ELUDRnK2jEiMTCBhIEYAagEkJAQgQAAoDdGJSIlMIGBAECBgBiBgYIdIoGDAEIdMYGB/ICBggUhAacAPwAcAKATQg0h9TKBggkigYAAgEL0BRnpIQGkBItIHEEN3SlBhACBwRwNGASBwR3K2AL9zSABpASEJBAhAACj40W9IQGkEIQhDbUlIYQhGQGkBIQkECENqSUhhAL9oSABpASEJBAhAACj40WVIAGljSQhAACgE0AhGYUkIYQEgcEdfSEBpBCGIQ11JSGEAIPbnAUZytllIWksYYRhGQGn/I9sAmENWS1hhASDABggaAgoYRkBpAiMTQxhDUUtYYRhGQGkBIxsEGENNS1hhAL9MSABpASMbBBhAACj40UhIAGlGSxhAACgE0BhGRUsYYQEgcEdDSEBpAiOYQ0FLWGEBIMAGAGhAHAAoBtEYRgBoASMbBBhDOksYYAAg6edwtYiwA0ZytsgdwQjJAAC/NEgAaQElLQQoQAAo+NE4SDBNKGEoRkBpASUoQy1NaGE/4AgpD9MQaBhgUGhYYAgzCDIIOQC/J0gAaQElLQQoQAAo+NEh4AAkBeAQeKUAbkZwUVIcZByMQvfTACQF4P8gZRitAG5GcFFkHAggQBqgQvXYAL8XSABpASUtBChAACj40QCYGGBYYAAhEkgAacAHwA8AKAXQDkgOTShhASAIsHC9ACm90QtIQGlACEAACU1oYQEgwAYAaEAcACgG0ChGAGgBJS0EqEMCTShgACDm5/rDAAAAIAJAqqoAAAAwAED/DwAAACwAQCMBZ0Wrie/N/wEAAAAAAAA=
+  load_address: 0x20000020
+  pc_init: 0x1
+  pc_uninit: 0x51
+  pc_program_page: 0x159
+  pc_erase_sector: 0xcd
+  pc_erase_all: 0x6b
+  data_section_offset: 0x25c
+  flash_properties:
+    address_range:
+      start: 0x8000000
+      end: 0x8008000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 400
+    erase_sector_timeout: 400
+    sectors:
+    - size: 0x800
+      address: 0x0
+- name: stm32u0xx_64k
+  description: STM32U0xx_64
+  default: true
+  instructions: gLWEsAOQApEBkgDwn/kVSRVICGAVSABowAMAKBLU/+cTSRRICGAUSAhgFEkGIAhgE0kUSAhgFEkUSAhgFEl/IAhg/+cTSABowA8AKAbQ/+cRSRJICGASSAhg/+cAIASwgL3ARhAgAkD6wwAAICACQAAwAECqqgAAVVUAAAQwAEAIMABA/w8AAAQsAED/AQAAACwAQBQgAkAIIAJAIwFnRauJ782BsACQBEkIaAEi0gcQQwhgACABsHBHwEYUIAJAg7ACkAGRaEYCcAEgA7BwR4C1grAA8Dr5/+cYSABowAMAKAHV/+f45xVJCGgEIhBDCGAIaAEiEgQQQwhg/+cPSABowAMAKAHV/+f45wtIAGgMSQhCBtD/5whJCkgIYAEgAZAH4AZJCGgEIpBDCGAAIAGQ/+cBmAKwgL3ARhAgAkAUIAJA+sMAAIC1hLACkADw/fgjSSNICGAjSQho/yLSAJBDCGACmB8i0gaAGAAKAZABmApoEEMCIhBDCGAIaAEiEgQQQwhg/+cVSABowAMAKAHV/+f45xJIAGgSSQhCBtD/5w9JD0gIYAEgA5AV4A5JCGgCIpBDCGABIMAGAGhAHAAoB9H/5wlJCGgBIhIEEEMIYP/nACADkP/nA5gEsIC9ECACQPrDAAAUIAJAACACQIC1jrAMkAuRCpIA8Kf4C5jAHQchiEMLkP/nS0gAaMADACgB1f/n+OdHSUhICGBISQhoASIQQwhg/+cLmAAoatD/5wuYCCga0//nCpgAaAyZCGAKmEBoDJlIYAyYCDAMkAqYCDAKkAuYCDgLkP/nNkgAaMADACgB1f/n+Oc+4AAgAZD/5wGYC5mIQg7S/+cKmAB4AZmKAAKpiFAKmEAcCpD/5wGYQBwBkOznACABkP/nAZgLmgghiRqIQgzS/+cBmAuZQBiCAAKp/yCIUP/nAZhAHAGQ7Of/5xtIAGjAAwAoAdX/5/jnApgMmQhggCECqEBYDJlIYAAgC5D/5xJIAGjABwAoBtD/5w9JE0gIYAEgDZAV4JHnDkoRaAEggUMRYMAGAGhAHAAoB9D/5wlJCGgBIhIEkEMIYP/nACANkP/nDZgOsIC9wEYQIAJA/wEAABQgAkAAIAJA+sMAAO/zEIDAB8APcrZwRwAAAAA=
+  load_address: 0x20000020
+  pc_init: 0x1
+  pc_uninit: 0xa5
+  pc_program_page: 0x1f1
+  pc_erase_sector: 0x149
+  pc_erase_all: 0xd1
+  data_section_offset: 0x358
+  flash_properties:
+    address_range:
+      start: 0x8000000
+      end: 0x8010000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 400
+    erase_sector_timeout: 400
+    sectors:
+    - size: 0x800
+      address: 0x0
+- name: stm32u0xx_16k
+  description: STM32U0xx_16
+  default: true
+  instructions: ELUDRnK2jEiMTCBhIEYAagEkJAQgQAAoDdGJSIlMIGBAECBgBiBgYIdIoGDAEIdMYGB/ICBggUhAacAPwAcAKATQg0h9TKBggkigYAAgEL0BRnpIQGkBItIHEEN3SlBhACBwRwNGASBwR3K2AL9zSABpASEJBAhAACj40W9IQGkEIQhDbUlIYQhGQGkBIQkECENqSUhhAL9oSABpASEJBAhAACj40WVIAGljSQhAACgE0AhGYUkIYQEgcEdfSEBpBCGIQ11JSGEAIPbnAUZytllIWksYYRhGQGn/I9sAmENWS1hhASDABggaAgoYRkBpAiMTQxhDUUtYYRhGQGkBIxsEGENNS1hhAL9MSABpASMbBBhAACj40UhIAGlGSxhAACgE0BhGRUsYYQEgcEdDSEBpAiOYQ0FLWGEBIMAGAGhAHAAoBtEYRgBoASMbBBhDOksYYAAg6edwtYiwA0ZytsgdwQjJAAC/NEgAaQElLQQoQAAo+NE4SDBNKGEoRkBpASUoQy1NaGE/4AgpD9MQaBhgUGhYYAgzCDIIOQC/J0gAaQElLQQoQAAo+NEh4AAkBeAQeKUAbkZwUVIcZByMQvfTACQF4P8gZRitAG5GcFFkHAggQBqgQvXYAL8XSABpASUtBChAACj40QCYGGBYYAAhEkgAacAHwA8AKAXQDkgOTShhASAIsHC9ACm90QtIQGlACEAACU1oYQEgwAYAaEAcACgG0ChGAGgBJS0EqEMCTShgACDm5/rDAAAAIAJAqqoAAAAwAED/DwAAACwAQCMBZ0Wrie/N/wEAAAAAAAA=
+  load_address: 0x20000020
+  pc_init: 0x1
+  pc_uninit: 0x51
+  pc_program_page: 0x159
+  pc_erase_sector: 0xcd
+  pc_erase_all: 0x6b
+  data_section_offset: 0x25c
+  flash_properties:
+    address_range:
+      start: 0x8000000
+      end: 0x8004000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 400
+    erase_sector_timeout: 400
+    sectors:
+    - size: 0x800
+      address: 0x0
+- name: stm32u0xx_128k
+  description: STM32U0xx_128
+  default: true
+  instructions: ELUDRnK2jEiMTCBhIEYAagEkJAQgQAAoDdGJSIlMIGBAECBgBiBgYIdIoGDAEIdMYGB/ICBggUhAacAPwAcAKATQg0h9TKBggkigYAAgEL0BRnpIQGkBItIHEEN3SlBhACBwRwNGASBwR3K2AL9zSABpASEJBAhAACj40W9IQGkEIQhDbUlIYQhGQGkBIQkECENqSUhhAL9oSABpASEJBAhAACj40WVIAGljSQhAACgE0AhGYUkIYQEgcEdfSEBpBCGIQ11JSGEAIPbnAUZytllIWksYYRhGQGn/I9sAmENWS1hhASDABggaAgoYRkBpAiMTQxhDUUtYYRhGQGkBIxsEGENNS1hhAL9MSABpASMbBBhAACj40UhIAGlGSxhAACgE0BhGRUsYYQEgcEdDSEBpAiOYQ0FLWGEBIMAGAGhAHAAoBtEYRgBoASMbBBhDOksYYAAg6edwtYiwA0ZytsgdwQjJAAC/NEgAaQElLQQoQAAo+NE4SDBNKGEoRkBpASUoQy1NaGE/4AgpD9MQaBhgUGhYYAgzCDIIOQC/J0gAaQElLQQoQAAo+NEh4AAkBeAQeKUAbkZwUVIcZByMQvfTACQF4P8gZRitAG5GcFFkHAggQBqgQvXYAL8XSABpASUtBChAACj40QCYGGBYYAAhEkgAacAHwA8AKAXQDkgOTShhASAIsHC9ACm90QtIQGlACEAACU1oYQEgwAYAaEAcACgG0ChGAGgBJS0EqEMCTShgACDm5/rDAAAAIAJAqqoAAAAwAED/DwAAACwAQCMBZ0Wrie/N/wEAAAAAAAA=
+  load_address: 0x20000020
+  pc_init: 0x1
+  pc_uninit: 0x51
+  pc_program_page: 0x159
+  pc_erase_sector: 0xcd
+  pc_erase_all: 0x6b
+  data_section_offset: 0x25c
+  flash_properties:
+    address_range:
+      start: 0x8000000
+      end: 0x8020000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 400
+    erase_sector_timeout: 400
+    sectors:
+    - size: 0x800
+      address: 0x0
+- name: stm32u0xx_256k
+  description: STM32U0xx_256
+  default: true
+  instructions: ELUDRnK2jEiMTCBhIEYAagEkJAQgQAAoDdGJSIlMIGBAECBgBiBgYIdIoGDAEIdMYGB/ICBggUhAacAPwAcAKATQg0h9TKBggkigYAAgEL0BRnpIQGkBItIHEEN3SlBhACBwRwNGASBwR3K2AL9zSABpASEJBAhAACj40W9IQGkEIQhDbUlIYQhGQGkBIQkECENqSUhhAL9oSABpASEJBAhAACj40WVIAGljSQhAACgE0AhGYUkIYQEgcEdfSEBpBCGIQ11JSGEAIPbnAUZytllIWksYYRhGQGn/I9sAmENWS1hhASDABggaAgoYRkBpAiMTQxhDUUtYYRhGQGkBIxsEGENNS1hhAL9MSABpASMbBBhAACj40UhIAGlGSxhAACgE0BhGRUsYYQEgcEdDSEBpAiOYQ0FLWGEBIMAGAGhAHAAoBtEYRgBoASMbBBhDOksYYAAg6edwtYiwA0ZytsgdwQjJAAC/NEgAaQElLQQoQAAo+NE4SDBNKGEoRkBpASUoQy1NaGE/4AgpD9MQaBhgUGhYYAgzCDIIOQC/J0gAaQElLQQoQAAo+NEh4AAkBeAQeKUAbkZwUVIcZByMQvfTACQF4P8gZRitAG5GcFFkHAggQBqgQvXYAL8XSABpASUtBChAACj40QCYGGBYYAAhEkgAacAHwA8AKAXQDkgOTShhASAIsHC9ACm90QtIQGlACEAACU1oYQEgwAYAaEAcACgG0ChGAGgBJS0EqEMCTShgACDm5/rDAAAAIAJAqqoAAAAwAED/DwAAACwAQCMBZ0Wrie/N/wEAAAAAAAA=
+  load_address: 0x20000020
+  pc_init: 0x1
+  pc_uninit: 0x51
+  pc_program_page: 0x159
+  pc_erase_sector: 0xcd
+  pc_erase_all: 0x6b
+  data_section_offset: 0x25c
+  flash_properties:
+    address_range:
+      start: 0x8000000
+      end: 0x8040000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 400
+    erase_sector_timeout: 400
+    sectors:
+    - size: 0x800
+      address: 0x0
diff --git a/probe-rs/targets/STM32WB_Series.yaml b/probe-rs/targets/STM32WB_Series.yaml
index e0d5ba29..c276a194 100644
--- a/probe-rs/targets/STM32WB_Series.yaml
+++ b/probe-rs/targets/STM32WB_Series.yaml
@@ -1,484 +1,810 @@
 name: STM32WB Series
-manufacturer:
-  id: 0x20
-  cc: 0x0
+generated_from_pack: true
+pack_file_release: 1.4.0
 variants:
-  - name: STM32WB30CEUx
+  - name: STM32WB10CCUx
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20008000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20003000
+        cores:
+          - main
+      - !Ram
+        name: SRAM2
+        range:
+          start: 0x20030000
+          end: 0x20039000
+        cores:
+          - main
+      - !Nvm
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8050000
+        is_boot_memory: true
+        cores:
+          - main
+    flash_algorithms:
+      - stm32wb1x_320_m4
+  - name: STM32WB15CCUx
+    cores:
+      - name: main
+        type: armv7em
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
+    memory_map:
+      - !Ram
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20003000
+        cores:
+          - main
+      - !Ram
+        name: SRAM2
+        range:
+          start: 0x20030000
+          end: 0x20039000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8080000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8050000
+        is_boot_memory: true
+        cores:
+          - main
+    flash_algorithms:
+      - stm32wb1x_320_m4
+  - name: STM32WB15CCUxE
+    cores:
+      - name: main
+        type: armv7em
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
+    memory_map:
+      - !Ram
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20003000
+        cores:
+          - main
+      - !Ram
+        name: SRAM2
+        range:
+          start: 0x20030000
+          end: 0x20039000
+        cores:
+          - main
+      - !Nvm
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8050000
+        is_boot_memory: true
+        cores:
+          - main
+    flash_algorithms:
+      - stm32wb1x_320_m4
+  - name: STM32WB15CCYx
+    cores:
+      - name: main
+        type: armv7em
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
+    memory_map:
+      - !Ram
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20003000
+        cores:
+          - main
+      - !Ram
+        name: SRAM2
+        range:
+          start: 0x20030000
+          end: 0x20039000
+        cores:
+          - main
+      - !Nvm
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8050000
+        is_boot_memory: true
+        cores:
+          - main
+    flash_algorithms:
+      - stm32wb1x_320_m4
+  - name: STM32WB1MMCHx
+    cores:
+      - name: main
+        type: armv7em
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
+    memory_map:
+      - !Ram
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20003000
+        cores:
+          - main
+      - !Ram
+        name: SRAM2
+        range:
+          start: 0x20030000
+          end: 0x20039000
+        cores:
+          - main
+      - !Nvm
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8050000
+        is_boot_memory: true
+        cores:
+          - main
+    flash_algorithms:
+      - stm32wb1x_320_m4
+  - name: STM32WB30CEUxA
+    cores:
+      - name: main
+        type: armv7em
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
+    memory_map:
+      - !Ram
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20008000
+        cores:
+          - main
+      - !Nvm
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8080000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
       - stm32wb3x_512_m4
-  - name: STM32WB35CCUx
+  - name: STM32WB35CCUxA
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20008000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20008000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8040000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8040000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
       - stm32wb3x_256_m4
-  - name: STM32WB35CEUx
+  - name: STM32WB35CEUxA
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20008000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20008000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8080000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8080000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
       - stm32wb3x_512_m4
   - name: STM32WB50CGUx
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20020000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20010000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8100000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8100000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_1024
   - name: STM32WB55CCUx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20030000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20010000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8040000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8040000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_256
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55CEUx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8080000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8080000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_512
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55CGUx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8100000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8100000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_1024
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55RCVx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20020000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20010000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8040000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8040000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_256
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55REVx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8080000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8080000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_512
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55RGVx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8100000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8100000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_1024
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55VCQx
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20020000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20010000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8040000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8040000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_256
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55VCYx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20020000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20010000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8040000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8040000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_256
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55VEQx
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8080000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8080000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_512
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55VEYx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8080000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8080000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_512
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55VGQx
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8100000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8100000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_1024
+      - stm32wb55x_35x_m4_opt
   - name: STM32WB55VGYx
-    part: 0x495
     cores:
       - name: main
         type: armv7em
-        core_access_options:
-          !Arm
-            ap: 0x0
-            psel: 0x0
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
+    memory_map:
+      - !Ram
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
+      - !Nvm
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8100000
+        is_boot_memory: true
+        cores:
+          - main
+    flash_algorithms:
+      - stm32wb5x_m4_1024
+      - stm32wb55x_35x_m4_opt
+  - name: STM32WB55VYYx
+    cores:
+      - name: main
+        type: armv7em
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
+    memory_map:
+      - !Ram
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
+      - !Nvm
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x80a0000
+        is_boot_memory: true
+        cores:
+          - main
+    flash_algorithms:
+      - stm32wb5x_m4_640
+      - stm32wb55x_35x_m4_opt
+  - name: STM32WB5MMGHx
+    cores:
+      - name: main
+        type: armv7em
+        core_access_options: !Arm
+          ap: 0
+          psel: 0
     memory_map:
       - !Ram
-          range:
-            start: 0x20000000
-            end: 0x20040000
-          is_boot_memory: false
-          cores:
-            - main
+        name: SRAM1
+        range:
+          start: 0x20000000
+          end: 0x20030000
+        cores:
+          - main
       - !Nvm
-          range:
-            start: 0x8000000
-            end: 0x8100000
-          is_boot_memory: true
-          cores:
-            - main
+        name: Main_Flash
+        range:
+          start: 0x8000000
+          end: 0x8100000
+        is_boot_memory: true
+        cores:
+          - main
     flash_algorithms:
-      - stm32wb_m4
+      - stm32wb5x_m4_1024
 flash_algorithms:
+  - name: stm32wb1x_320_m4
+    description: STM32WB1x_M4 320 Flash
+    default: true
+    instructions: QLpwR8C6cEdP6jAAcEcAAHK2kUhBaQApA9qQSYFgkEmBYABqwAMQ1I5ISvaqIQFgSRABYAYhQWBA9v9xgWDIEIlJCGB/IAkfCGBitgAgcEeBSEFpQfAAQUFhACBwRxC1crZ9SUTy+jIKYUH2+HQE6hAjSGmgQ0hhCGnAA/zUCGkAA/zUCGlAA/zUSGlD8AIDGENIYUhpQPSAMEhhAL8AvwhpwAP81AhpQAP81AhpAAP81EhpIPACAEhhCGkQQgLQCmEBIBC9T/AAYABoQBwD0QhoQPSAMAhgYrYAIBC9MLVytl1IAWpfSssFSvaqIRDVkPiAAF1JT/AAZAHrwCUE4CBG//es/wT1AGSsQvjZIeARYANp2wP71ANpRPL6NCNDA2FDaUPwBANDYUNpQ/SAM0NhAOARYANp2wP71EFpIfAEAUFhAWkhQgTQAWkhQwFhASAwvWK2ACAwvS3p8E2IsHK2SvaqKt/4/LA7TgHgy/gAoDNp2wP61ETy+jc3YU/wAQ7G+BTg7EZU4Mb4FOAIKRPTE2gDYFNoQ2AAvwC/VEZbRgDgHGA1ae0D+9QzaTtCO9EIMAg5CDI84AAjBOAS+AFLTPgjQFsci0L40wAj/yTB8QgFBOAD6wEIWxxM+ChAnUL42N3pABMB6wMhApsDnBsEA+sEYxlEAJHd6QQTAesDIQabB5wbBAPrBGMZRAGRAJkBYAGZQWAAvwC/ACEzadsD/NQzaTtCBNA3YQEgCLC96PCNACmo0XBpIPABAHBhT/AAYABoQBwD0DBoIPSAMDBgYrYAIOrnAEAAWCMBZ0Wrie/NADAAQAQsAEAA+P8HAAAAAA==
+    load_address: 0x20000020
+    pc_init: 0x11
+    pc_uninit: 0x51
+    pc_program_page: 0x15b
+    pc_erase_sector: 0x5f
+    pc_erase_all: 0xdf
+    data_section_offset: 0x270
+    flash_properties:
+      address_range:
+        start: 0x8000000
+        end: 0x8050000
+      page_size: 0x400
+      erased_byte_value: 0xff
+      program_page_timeout: 400
+      erase_sector_timeout: 400
+      sectors:
+        - size: 0x800
+          address: 0x0
+
+  - name: stm32wb3x_512_m4
+    description: STM32WB3_M4 512 Flash
+    default: true
+    instructions: QLpwR8C6cEeQSUAKCEBwR7/zT49wR3K2jUhBaQApA9qMSYFgjEmBYABqwAMN1IxIikkBYEkQAWAGIUFgiUmBYIlIyRBBYH8hAWBitgAgcEd/SEFpQgQRQ0FhACBwR3C1crb/99H/ekkKadID/NQKaVID/NQKaRID/NQLaXtKE0MLYUtpcUzkQyNAS2FMaQIjGEMEQ0xhSGncAyBDSGFvSG9NAOAoYA5p9gP71EhpmENIYQhpEEIE0AhpEEMIYQEgcL0BIMAGAGhAHALRCGggQwhgYrYAIHC9cLVytlxIAWpfSssFXUkR1VlIYUmAMAB4ASQAA0UY5AaWFAPgIEb/967/pBmsQvnZH+ARYANp2wP71ARpVUscQwRhRWkEJCVDRWFFaaYDNUNFYQDgEWAFae0D+9RBaaFDQWEBaRlCBNABaRlDAWEBIHC9YrYAIHC98LWIsHK2PksC4EFNP0wsYBxp5AP51EFMHGEBJFxhWuA3TAEjY2EIKRXTE2gDYFNoQ2C/80+PNUw1TTFLAOAsYB5p9gP71BtpNEwjQj3RCDAIOQgyP+AAI25GBOAUeJ0AUhx0UVsci0L40wAj/yQIJW0aA+BfGL8A9FFbHJ1C+dgBmwCZGwLLGAKZA5wJBCQGCRlZGACRBZsEmRsCyxgGmQecCQQkBgkZWRgBkQCZAWABmUFgv/NPjxFLACEcaeQD/NQcaRVLHEIF0A1JE0gIYQEgCLDwvQApotEJSEFpSQhJAEFhQQMJaEkcBNABaAEiEgSRQwFgYrYAIOrn+B8AAABAAFgjAWdFq4nvzaqqAAAAMABA/w8AAAAsAED6QwAAAPD/BwAAAAA=
+    load_address: 0x20000020
+    pc_init: 0x17
+    pc_uninit: 0x51
+    pc_program_page: 0x151
+    pc_erase_sector: 0x5f
+    pc_erase_all: 0xd9
+    data_section_offset: 0x274
+    flash_properties:
+      address_range:
+        start: 0x8000000
+        end: 0x8080000
+      page_size: 0x400
+      erased_byte_value: 0xff
+      program_page_timeout: 400
+      erase_sector_timeout: 400
+      sectors:
+        - size: 0x1000
+          address: 0x0
+
   - name: stm32wb3x_256_m4
     description: STM32WB3_M4 256 Flash
-    cores:
-      - main
     default: true
-    instructions: YUhBaQApA9pgSYFgYEmBYAAgcEdcSEFpQgQRQ0FhACBwRxC1WEhbSVtKAOARYANp2wP71FlKAmEBackD/NQBaQkD/NQBaUkD/NQBaVRLGUMBYUFpBCMZQ0FhQWmcAyFDQWEBackD/NQBaUkD/NQBaQkD/NRBaZlDQWEAIUFhAWkRQgLQAmEBIBC9ACAQvRC1PUlCSgphS2lCTCNAS2FACuNDGEALadsD/NQLaVsD/NQLaRsD/NRMaQIjGEMEQ0xhSGncAyBDSGEAvwC/CGnAA/zUCGlAA/zUCGkAA/zUSGmYQ0hhACBIYQhpEEIC0AphASAQvQEgwAYAaEAcAtEIaCBDCGAAIBC9cLXJHR5LyQgjTckAHWFcaQEmNENcYRpOQDYe4B1hHGnkA/zUHGlkA/zUHGkkA/zUFGgEYFRoRGAcaeQD/NQcaWQD/NQcaSQD/NQ0aggwCDkIMuQHAdABIHC9ACne0VhpQAhAAFhhASDABgBoQBwE0BhoASEJBIhDGGAAIHC9AAAAQABYIwFnRauJ782qqgAAADAAQPpDAAD/AQAAB+D//wAAAAA=
-    pc_init: 0x1
-    pc_uninit: 0x15
-    pc_program_page: 0x109
-    pc_erase_sector: 0x8f
-    pc_erase_all: 0x23
-    data_section_offset: 0x1a8
+    instructions: QLpwR8C6cEeQSUAKCEBwR7/zT49wR3K2jUhBaQApA9qMSYFgjEmBYABqwAMN1IxIikkBYEkQAWAGIUFgiUmBYIlIyRBBYH8hAWBitgAgcEd/SEFpQgQRQ0FhACBwR3C1crb/99H/ekkKadID/NQKaVID/NQKaRID/NQLaXtKE0MLYUtpcUzkQyNAS2FMaQIjGEMEQ0xhSGncAyBDSGFvSG9NAOAoYA5p9gP71EhpmENIYQhpEEIE0AhpEEMIYQEgcL0BIMAGAGhAHALRCGggQwhgYrYAIHC9cLVytlxIAWpfSssFXUkR1VlIYUmAMAB4ASQAA0UY5AaWFAPgIEb/967/pBmsQvnZH+ARYANp2wP71ARpVUscQwRhRWkEJCVDRWFFaaYDNUNFYQDgEWAFae0D+9RBaaFDQWEBaRlCBNABaRlDAWEBIHC9YrYAIHC98LWIsHK2PksC4EFNP0wsYBxp5AP51EFMHGEBJFxhWuA3TAEjY2EIKRXTE2gDYFNoQ2C/80+PNUw1TTFLAOAsYB5p9gP71BtpNEwjQj3RCDAIOQgyP+AAI25GBOAUeJ0AUhx0UVsci0L40wAj/yQIJW0aA+BfGL8A9FFbHJ1C+dgBmwCZGwLLGAKZA5wJBCQGCRlZGACRBZsEmRsCyxgGmQecCQQkBgkZWRgBkQCZAWABmUFgv/NPjxFLACEcaeQD/NQcaRVLHEIF0A1JE0gIYQEgCLDwvQApotEJSEFpSQhJAEFhQQMJaEkcBNABaAEiEgSRQwFgYrYAIOrn+B8AAABAAFgjAWdFq4nvzaqqAAAAMABA/w8AAAAsAED6QwAAAPD/BwAAAAA=
+    load_address: 0x20000020
+    pc_init: 0x17
+    pc_uninit: 0x51
+    pc_program_page: 0x151
+    pc_erase_sector: 0x5f
+    pc_erase_all: 0xd9
+    data_section_offset: 0x274
     flash_properties:
       address_range:
         start: 0x8000000
         end: 0x8040000
       page_size: 0x400
       erased_byte_value: 0xff
-      program_page_timeout: 0x190
-      erase_sector_timeout: 0x190
+      program_page_timeout: 400
+      erase_sector_timeout: 400
       sectors:
         - size: 0x1000
           address: 0x0
-  - name: stm32wb3x_512_m4
-    description: STM32WB3_M4 512 Flash
-    cores:
-      - main
+
+  - name: stm32wb5x_m4_1024
+    description: STM32WB5x_M4_1024 Flash
     default: true
-    instructions: YUhBaQApA9pgSYFgYEmBYAAgcEdcSEFpQgQRQ0FhACBwRxC1WEhbSVtKAOARYANp2wP71FlKAmEBackD/NQBaQkD/NQBaUkD/NQBaVRLGUMBYUFpBCMZQ0FhQWmcAyFDQWEBackD/NQBaUkD/NQBaQkD/NRBaZlDQWEAIUFhAWkRQgLQAmEBIBC9ACAQvRC1PUlCSgphS2lCTCNAS2FACuNDGEALadsD/NQLaVsD/NQLaRsD/NRMaQIjGEMEQ0xhSGncAyBDSGEAvwC/CGnAA/zUCGlAA/zUCGkAA/zUSGmYQ0hhACBIYQhpEEIC0AphASAQvQEgwAYAaEAcAtEIaCBDCGAAIBC9cLXJHR5LyQgjTckAHWFcaQEmNENcYRpOQDYe4B1hHGnkA/zUHGlkA/zUHGkkA/zUFGgEYFRoRGAcaeQD/NQcaWQD/NQcaSQD/NQ0aggwCDkIMuQHAdABIHC9ACne0VhpQAhAAFhhASDABgBoQBwE0BhoASEJBIhDGGAAIHC9AAAAQABYIwFnRauJ782qqgAAADAAQPpDAAD/AQAAB+D//wAAAAA=
+    instructions: QLpwR8C6cEdP6jAAcEcAAMDzTCBwR7/zT49wR3K2kkhBaQApA9qRSYFgkUmBYABqwAMQ1I9ISvaqIQFgSRABYAYhQWBA9v9xgWDIEIpJCGB/IAkfCGBitgAgcEeCSEFpQfAAQUFhACBwRxC1crbA80wifUgBackD/NQBaUkD/NQBaQkD/NQBaUTy+jQhQwFhQWlB9vhzmUNBYUFpQvACAhFDQWFBaUH0gDFBYUr2qiFwSgDgEWADadsD+9RBaSHwAgFBYQFpIUIE0AFpIUMBYQEgEL1P8ABhCWhJHAPRAWhB9IAxAWBitgAgEL0wtXK2XUgBal9KywVK9qohENWQ+IAAXklP8ABkAesANQTgIEb/96v/BPWAVKxC+Nkh4BFgA2nbA/vUA2lE8vo0I0MDYUNpQ/AEA0NhQ2lD9IAzQ2EA4BFgA2nbA/vUQWkh8AQBQWEBaSFCBNABaSFDAWEBIDC9YrYAIDC9LenwTYiwcrZK9qoq3/j8sDtOAeDL+ACgM2nbA/rURPL6NzdhT/ABDsb4FODsRlTgxvgU4AgpE9MTaANgU2hDYL/zT49URltGAOAcYDVp7QP71DNpO0I70QgwCDkIMjzgACME4BL4AUtM+CNAWxyLQvjTACP/JMHxCAUE4APrAQhbHEz4KECdQvjY3ekAEwHrAyECmwOcGwQD6wRjGUQAkd3pBBMB6wMhBpsHnBsEA+sEYxlEAZEAmQFgAZlBYL/zT48AITNp2wP81DNpO0IE0DdhASAIsL3o8I0AKajRcGkg8AEAcGFP8ABgAGhAHAPQMGgg9IAwMGBitgAg6ucAAABAAFgjAWdFq4nvzQAwAEAELABAAPD/BwAAAAA=
+    load_address: 0x20000020
+    pc_init: 0x1d
+    pc_uninit: 0x5d
+    pc_program_page: 0x169
+    pc_erase_sector: 0x6b
+    pc_erase_all: 0xed
+    data_section_offset: 0x280
+    flash_properties:
+      address_range:
+        start: 0x8000000
+        end: 0x8100000
+      page_size: 0x400
+      erased_byte_value: 0xff
+      program_page_timeout: 400
+      erase_sector_timeout: 400
+      sectors:
+        - size: 0x1000
+          address: 0x0
+
+  - name: stm32wb5x_m4_256
+    description: STM32WB5x_M4_256 Flash
+    default: true
+    instructions: QLpwR8C6cEdP6jAAcEcAAMDzTCBwR7/zT49wR3K2kkhBaQApA9qRSYFgkUmBYABqwAMQ1I9ISvaqIQFgSRABYAYhQWBA9v9xgWDIEIpJCGB/IAkfCGBitgAgcEeCSEFpQfAAQUFhACBwRxC1crbA80wifUgBackD/NQBaUkD/NQBaQkD/NQBaUTy+jQhQwFhQWlB9vhzmUNBYUFpQvACAhFDQWFBaUH0gDFBYUr2qiFwSgDgEWADadsD+9RBaSHwAgFBYQFpIUIE0AFpIUMBYQEgEL1P8ABhCWhJHAPRAWhB9IAxAWBitgAgEL0wtXK2XUgBal9KywVK9qohENWQ+IAAXklP8ABkAesANQTgIEb/96v/BPWAVKxC+Nkh4BFgA2nbA/vUA2lE8vo0I0MDYUNpQ/AEA0NhQ2lD9IAzQ2EA4BFgA2nbA/vUQWkh8AQBQWEBaSFCBNABaSFDAWEBIDC9YrYAIDC9LenwTYiwcrZK9qoq3/j8sDtOAeDL+ACgM2nbA/rURPL6NzdhT/ABDsb4FODsRlTgxvgU4AgpE9MTaANgU2hDYL/zT49URltGAOAcYDVp7QP71DNpO0I70QgwCDkIMjzgACME4BL4AUtM+CNAWxyLQvjTACP/JMHxCAUE4APrAQhbHEz4KECdQvjY3ekAEwHrAyECmwOcGwQD6wRjGUQAkd3pBBMB6wMhBpsHnBsEA+sEYxlEAZEAmQFgAZlBYL/zT48AITNp2wP81DNpO0IE0DdhASAIsL3o8I0AKajRcGkg8AEAcGFP8ABgAGhAHAPQMGgg9IAwMGBitgAg6ucAAABAAFgjAWdFq4nvzQAwAEAELABAAPD/BwAAAAA=
+    load_address: 0x20000020
+    pc_init: 0x1d
+    pc_uninit: 0x5d
+    pc_program_page: 0x169
+    pc_erase_sector: 0x6b
+    pc_erase_all: 0xed
+    data_section_offset: 0x280
+    flash_properties:
+      address_range:
+        start: 0x8000000
+        end: 0x8040000
+      page_size: 0x400
+      erased_byte_value: 0xff
+      program_page_timeout: 400
+      erase_sector_timeout: 400
+      sectors:
+        - size: 0x1000
+          address: 0x0
+
+  - name: stm32wb55x_35x_m4_opt
+    description: STM32WB55x/35x Flash Options
+    instructions: RPIQAMX2AAABackDQ/IAAcTyAAEH1EXyVVIKYAYiSmBA9v9yimBA8iMSxPJnUkD4CCxI9qsSzPbvUkD4CCy/80+PAmjSAxLUQvY7IsD2GQJA+AQsRvZ/YsT2XUJA+AQsv/NPjwJo0gMV1AAgcEdK9qoiCmADaNsD5tUKYANo2wNCvwpgA2hf6sMz3dUKYANo2wPu1NjnSvaqIgpgA2jbA+PVCmADaNsDQr8KYANoX+rDM9rVCmADaNsD7tTV5wC/RPIQAMX2AABP8IBBQWC/80+PAWjJA0PyAAHE8gABCdRP8ABCQmC/80+PAmjSAxXUACBwR0r2qiIKYANo2wPv1QpgA2jbA0K/CmADaF/qwzPm1QpgA2jbA+7U4edK9qoiCmADaNsD49UKYANo2wNCvwpgA2hf6sMz2tUKYANo2wPu1NXnACBwR0TyEABP8qoSxfYAAEzy+jzD9v9SwPgAwAJhQPL/Ek/wAENCYYNh/yPDYQNiQmIAIoJiTPIAAs/2/3LCYk/0ADJCYL/zT48CaNIDCdQBaBHqDA8PvwAgTPL6MQFgASBwR0PyAALE8gACSvaqIxNgAWjJA+vVE2ABaMkDQr8TYAFoX+rBMeLVE2ABaMkD7tTd5wAgcEct6fBNhLARfBBoAJERfUf2/2wCkRF+FXkDkVF+VnnXepL4DICS+A7gkvgSoJL4FbABkc72j3wTf1F/EokM6gAMRPIQAMX2AABM8vo0ReoGJk/2AGVC6gdiT/YAZwRgTPCAVM/2/3XH9v93RPThBC5DOkMEYUZhgmFI6g5CQvD/IsJhAJpD6gEhQuoKQkLw/yICYgKaQuoLIipDQmIDmgGfQuoHIipDgmKl9XhSEUPBYk/0ADG/80+PQWC/80+PAWjJAw3UAWhM8voyEUIg0AFoTPL6MhFDAWABIASwvejwjUPyAAHE8gABSvaqIwtgAmjSA+fVC2ACaNIDQr8LYAJoX+rCMt7VC2ACaNID7tTZ5wAgBLC96PCNELVI8gAMwfb/fNL4AOC/80+P3PgAMI7qAw5H9v9jzvaPcx7qAw8YvxC9kvgE4Nz4CDBUeW/zXyNk8wguc0UcvwEwEL2y+Ajg1Hrc+BAwTuoEZGNAQPL/FMjyAAQjQhy/AjAQvZL4DOCUe9z4GDBO6gREP/qD86NCHL8DMBC9kvgQ4JR83PggME7qBEQ/+oPzo0IcvwQwEL1UfZL4FODc+CgwJAIE9IB0b/NfI3REo0IcvwUwEL1UfpL4GODc+DAwJAIE9IB0b/NfI3REo0IcvwYwEL0Tf1J/3PhoQBICAvR8Um/znzQaRJRCHL8HMBC9CEQQvQAAAAA=
+    load_address: 0x20000020
     pc_init: 0x1
-    pc_uninit: 0x15
-    pc_program_page: 0x109
-    pc_erase_sector: 0x8f
-    pc_erase_all: 0x23
-    data_section_offset: 0x1a8
+    pc_uninit: 0xc1
+    pc_program_page: 0x1dd
+    pc_erase_sector: 0x1d9
+    pc_erase_all: 0x149
+    data_section_offset: 0x3e8
+    flash_properties:
+      address_range:
+        start: 0x1fff8000
+        end: 0x1fff8020
+      page_size: 0x20
+      erased_byte_value: 0xff
+      program_page_timeout: 3000
+      erase_sector_timeout: 3000
+      sectors:
+        - size: 0x20
+          address: 0x0
+
+  - name: stm32wb5x_m4_512
+    description: STM32WB5x_M4_512 Flash
+    default: true
+    instructions: QLpwR8C6cEdP6jAAcEcAAMDzTCBwR7/zT49wR3K2kkhBaQApA9qRSYFgkUmBYABqwAMQ1I9ISvaqIQFgSRABYAYhQWBA9v9xgWDIEIpJCGB/IAkfCGBitgAgcEeCSEFpQfAAQUFhACBwRxC1crbA80wifUgBackD/NQBaUkD/NQBaQkD/NQBaUTy+jQhQwFhQWlB9vhzmUNBYUFpQvACAhFDQWFBaUH0gDFBYUr2qiFwSgDgEWADadsD+9RBaSHwAgFBYQFpIUIE0AFpIUMBYQEgEL1P8ABhCWhJHAPRAWhB9IAxAWBitgAgEL0wtXK2XUgBal9KywVK9qohENWQ+IAAXklP8ABkAesANQTgIEb/96v/BPWAVKxC+Nkh4BFgA2nbA/vUA2lE8vo0I0MDYUNpQ/AEA0NhQ2lD9IAzQ2EA4BFgA2nbA/vUQWkh8AQBQWEBaSFCBNABaSFDAWEBIDC9YrYAIDC9LenwTYiwcrZK9qoq3/j8sDtOAeDL+ACgM2nbA/rURPL6NzdhT/ABDsb4FODsRlTgxvgU4AgpE9MTaANgU2hDYL/zT49URltGAOAcYDVp7QP71DNpO0I70QgwCDkIMjzgACME4BL4AUtM+CNAWxyLQvjTACP/JMHxCAUE4APrAQhbHEz4KECdQvjY3ekAEwHrAyECmwOcGwQD6wRjGUQAkd3pBBMB6wMhBpsHnBsEA+sEYxlEAZEAmQFgAZlBYL/zT48AITNp2wP81DNpO0IE0DdhASAIsL3o8I0AKajRcGkg8AEAcGFP8ABgAGhAHAPQMGgg9IAwMGBitgAg6ucAAABAAFgjAWdFq4nvzQAwAEAELABAAPD/BwAAAAA=
+    load_address: 0x20000020
+    pc_init: 0x1d
+    pc_uninit: 0x5d
+    pc_program_page: 0x169
+    pc_erase_sector: 0x6b
+    pc_erase_all: 0xed
+    data_section_offset: 0x280
     flash_properties:
       address_range:
         start: 0x8000000
         end: 0x8080000
       page_size: 0x400
       erased_byte_value: 0xff
-      program_page_timeout: 0x190
-      erase_sector_timeout: 0x190
+      program_page_timeout: 400
+      erase_sector_timeout: 400
       sectors:
         - size: 0x1000
           address: 0x0
-  - name: stm32wb_m4
-    description: STM32WB_M4 Flash
-    cores:
-      - main
+
+  - name: stm32wb5x_m4_640
+    description: STM32WB5x_M4_640 Flash
     default: true
-    instructions: Qfb4cQHqUCBwR0pISEmBYElJgWAAIHBHRkhBaUHwAEFBYQAgcEcBIHBHELVK9qoiQklASADgCmADadsD+9RE8vo0BGFI8gQDQ2FDaUP0gDNDYQDgCmADadsD+9QAIUFhAWkhQgLQBGEBIBC9ACAQvUH2+HEB6lAiELUuSAFpEfRAP/vRAWlJA/zUAWkJA/zURPL6NARhQvACAUFhQWlB9IAxQWFK9qohJEoA4BFgA2nbA/vUACFBYQFpIUIC0ARhASAQvQAgEL0QtRpLyR1A8v8UIfAHARxhASRcYR/gHGkU9EA/+9EcaWQD/NQcaSQD/NQUaARgVGhEYBxpFPRAP/vRHGlkA/zUHGkkA/zUHGmkBwHVASAQvQgwCDkIMgAp3dFYaSDwAQBYYQAgEL0AACMBZ0UAQABYq4nvzQAwAEAAAAAA
-    pc_init: 0xb
-    pc_uninit: 0x19
-    pc_program_page: 0xc9
-    pc_erase_sector: 0x71
-    pc_erase_all: 0x2b
-    data_section_offset: 0x140
+    instructions: QLpwR8C6cEdP6jAAcEcAAMDzTCBwR7/zT49wR3K2kkhBaQApA9qRSYFgkUmBYABqwAMQ1I9ISvaqIQFgSRABYAYhQWBA9v9xgWDIEIpJCGB/IAkfCGBitgAgcEeCSEFpQfAAQUFhACBwRxC1crbA80wifUgBackD/NQBaUkD/NQBaQkD/NQBaUTy+jQhQwFhQWlB9vhzmUNBYUFpQvACAhFDQWFBaUH0gDFBYUr2qiFwSgDgEWADadsD+9RBaSHwAgFBYQFpIUIE0AFpIUMBYQEgEL1P8ABhCWhJHAPRAWhB9IAxAWBitgAgEL0wtXK2XUgBal9KywVK9qohENWQ+IAAXklP8ABkAesANQTgIEb/96v/BPWAVKxC+Nkh4BFgA2nbA/vUA2lE8vo0I0MDYUNpQ/AEA0NhQ2lD9IAzQ2EA4BFgA2nbA/vUQWkh8AQBQWEBaSFCBNABaSFDAWEBIDC9YrYAIDC9LenwTYiwcrZK9qoq3/j8sDtOAeDL+ACgM2nbA/rURPL6NzdhT/ABDsb4FODsRlTgxvgU4AgpE9MTaANgU2hDYL/zT49URltGAOAcYDVp7QP71DNpO0I70QgwCDkIMjzgACME4BL4AUtM+CNAWxyLQvjTACP/JMHxCAUE4APrAQhbHEz4KECdQvjY3ekAEwHrAyECmwOcGwQD6wRjGUQAkd3pBBMB6wMhBpsHnBsEA+sEYxlEAZEAmQFgAZlBYL/zT48AITNp2wP81DNpO0IE0DdhASAIsL3o8I0AKajRcGkg8AEAcGFP8ABgAGhAHAPQMGgg9IAwMGBitgAg6ucAAABAAFgjAWdFq4nvzQAwAEAELABAAPD/BwAAAAA=
+    load_address: 0x20000020
+    pc_init: 0x1d
+    pc_uninit: 0x5d
+    pc_program_page: 0x169
+    pc_erase_sector: 0x6b
+    pc_erase_all: 0xed
+    data_section_offset: 0x280
     flash_properties:
       address_range:
         start: 0x8000000
-        end: 0x8100000
+        end: 0x80a0000
       page_size: 0x400
       erased_byte_value: 0xff
-      program_page_timeout: 0x190
-      erase_sector_timeout: 0x190
+      program_page_timeout: 400
+      erase_sector_timeout: 400
       sectors:
         - size: 0x1000
           address: 0x0
diff --git a/target-gen/Cargo.toml b/target-gen/Cargo.toml
index c5940d6f..4df59055 100644
--- a/target-gen/Cargo.toml
+++ b/target-gen/Cargo.toml
@@ -15,9 +15,7 @@ license.workspace = true
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-probe-rs = { path = "../probe-rs", version = "0.23.0", default-features = false, features = [
-    "rtt",
-] }
+probe-rs = { path = "../probe-rs", version = "0.23.0", default-features = false }
 probe-rs-target = { path = "../probe-rs-target", version = "0.23.0", default-features = false }
 cmsis-pack = { version = "0.6.3" }
 goblin = { version = "0.8.0", default-features = false, features = [
@@ -33,8 +31,8 @@ log = "0.4.21"
 zip = "0.6.6"
 clap = { version = "4.5", features = ["derive"] }
 colored = "2"
-anyhow = "1.0.81"
-reqwest = { version = "0.12.2", features = ["json", "rustls-tls"], default-features = false }
+anyhow = "1.0.82"
+reqwest = { version = "0.12.3", features = ["json", "rustls-tls"], default-features = false }
 futures = "0.3.30"
 tokio = { version = "1.37.0", features = ["macros", "rt", "rt-multi-thread"] }
 tracing-subscriber = { version = "0.3.18", features = [


Test patch:
diff --git a/.github/workflows/smoketest.yml b/.github/workflows/smoketest.yml
index fbb80207..fec93f1e 100644
--- a/.github/workflows/smoketest.yml
+++ b/.github/workflows/smoketest.yml
@@ -23,7 +23,7 @@ jobs:
         run: rustup target add aarch64-unknown-linux-gnu
 
       - name: Install cross 
-        uses: taiki-e/install-action@v2.32.0
+        uses: taiki-e/install-action@v2.32.17
         with:
           tool: cross
 
diff --git a/probe-rs/src/bin/probe-rs/cmd/run/test_run_mode.rs b/probe-rs/src/bin/probe-rs/cmd/run/test_run_mode.rs
index 8a75ebcc..fc74c32d 100644
--- a/probe-rs/src/bin/probe-rs/cmd/run/test_run_mode.rs
+++ b/probe-rs/src/bin/probe-rs/cmd/run/test_run_mode.rs
@@ -40,6 +40,16 @@ pub struct TestOptions {
     #[clap(long = "exact", help_heading = "TEST OPTIONS")]
     pub exact: bool,
 
+    /// A list of filters. Tests whose names contain parts of any of these
+    /// filters are skipped.
+    #[clap(
+        long = "skip-test",
+        value_name = "FILTER",
+        help_heading = "TEST OPTIONS",
+        help = "Skip tests whose names contain FILTER (this flag can be used multiple times)"
+    )]
+    pub skip_test: Vec<String>,
+
     /// Options which are ignored, but exist for compatibility with libtest.
     /// E.g. so that vscode and intellij can invoke the test runner with the args they are used to
     #[clap(flatten)]
@@ -75,6 +85,7 @@ impl TestRunMode {
                 list: test_options.list,
                 exact: test_options.exact,
                 format: test_options.format,
+                skip: test_options.skip_test.clone(),
                 filter: if test_options.filter.is_empty() {
                     None
                 } else {
diff --git a/smoke-tester/Cargo.toml b/smoke-tester/Cargo.toml
index ef27a3e8..8adc77a1 100644
--- a/smoke-tester/Cargo.toml
+++ b/smoke-tester/Cargo.toml
@@ -11,7 +11,7 @@ publish = false
 [dependencies]
 probe-rs = { workspace = true }
 toml = "0.8.12"
-anyhow = "1.0.81"
+anyhow = "1.0.82"
 serde = { version = "1", features = ["derive"] }
 pretty_env_logger = "0.5.0"
 log = "0.4.21"