Open-source project
Marus/cortex-debug avatar
Marus/cortex-debug

Cortex-Debug: a debug adapter that speaks to real GDB servers

Visual Studio Code extension for enhancing debug capabilities for Cortex-M Microcontrollers

1,256 stars289 forksTypeScriptMIT

At a glance

What is it?
Cortex-Debug is a Visual Studio Code extension for debugging ARM Cortex-M and other microcontrollers, and it does not implement debugging itself. It drives an external GDB server, from J-Link, OpenOCD, ST-LINK, pyOCD, or the Black Magic Probe, and adds the trace, graphing, and register views on top of the VS Code interface.
Who is it for?
Adopt Cortex-Debug if you develop firmware for Cortex-M and want the VS Code debugging experience with trace decoding and ITM graphing on top of a vendor GDB server. Do not adopt it if you are on a vendor toolchain that already integrates well, or if you need a fully vendor-neutral stack, since the extension deliberately leans on the GDB servers the vendors ship.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The extension is a front end, not an engine

Cortex-Debug is a Visual Studio Code extension for enhancing debug capabilities for Cortex-M microcontrollers, and the most important thing to understand about it is what it does not do. It does not talk to the silicon. It drives a GDB server that someone else ships, and it renders what that server reports.

The supported server list is the extension's compatibility surface. It supports J-Link, the OpenOCD GDB Server, STMicroelectronic's ST-LINK GDB server, pyOCD, and the Black Magic Probe, and it has partial support for the texane and stlink, or st-util, GDB servers, where SWO can only be captured via a serial port. The README also notes that if a chip vendor ships its own OpenOCD version, use nothing but that, which is the single most useful piece of advice in the document for anyone with a vendor board.

The extension's own name is a constraint rather than a choice. The README says that while the extension name cannot be changed due to VSCode Marketplace rules, it can be used by non Cortex-M devices and non ARM devices, and that people have reported using it with Cortex-R and Cortex-A, Xtensa, RISC-V, and even x86, with the caveat that your mileage may vary.

That is a useful signal about how portable the underlying approach is. A VS Code debug adapter that speaks GDB's remote protocol does not care what is on the other end, so the same extension covers a wide range of hardware as long as something provides a GDB server.

The project is MIT licensed, written in TypeScript, and the last push to the repository was on 2026-10-13. The recent releases are all pre-releases, v1.13.0-pre11 from 2026-10-13, v1.13.0-pre10 from 2026-07-31, and v1.13.0-pre9 from 2026-06-15.

The pre-release versioning convention

Cortex-Debug uses the pre-release versioning system specified by Microsoft, which allows distribution of pre-releases through the marketplace. You can enable or disable pre-releases within VS Code for this extension and you will automatically get new pre-releases, and by default pre-releases are disabled.

The stated reason for the scheme is that pre-releases allow testing of bug fixes and new features, and they let you participate during the formation of a feature or of how an issue gets addressed. That is an unusually candid description of a pre-release channel, and it is the model that the whole 1.13.0 line follows.

The mechanism has a quirk worth knowing. Extensions use semantic versioning, major.minor.patch, and with the Microsoft convention, if the minor version is odd then it is a pre-release. So the stable line is an even minor version and the pre-release line is an odd one. In practice that means the version number itself tells you whether you are on a stable build or a pre-release, without looking at the marketplace listing.

The project also has a planned features list, which is short. Additional graphing options are the first entry, and the rest is a TODO file in the repository. A short roadmap for a project of this size is worth noting, because the feature set described in the README is clearly the product of years of accumulated work rather than of a stated plan.

SWO, RTT, and the trace decoding features

The trace features are where Cortex-Debug goes beyond a debugger front end, and they are the part most likely to change how you work on firmware.

SWO decoding covers console text output and binary data, with the supported binary formats being signed and unsigned 32-bit integers, Q16.16 fixed point integers, and single precision floating point values. The registers that are part of the DWT, TPIU, and ITM debug components are automatically configured and do not need to be set in firmware, though firmware may still need to enable the SWO output pin because that part of the setup is microcontroller dependent. Decoding ETM data over the SWO pin is not currently supported.

Live graphing of decoded ITM data is supported, and so are custom ITM data decoders, where you define JavaScript modules to decode complex data formats streamed over one or more ITM ports. The decoded data can be printed to an output window or sent to the graphing system, and if you are using TCP/IP instead of the SWO pin you can use a variety of tools to connect to that port. That extensibility point is the interesting one, because it means a project-specific binary protocol can be made readable without patching the extension.

SEGGER Real Time Trace, or RTT, is supported using the OpenOCD and J-Link GDB servers, and all the features supported for SWO, meaning text, binary, and graphing, are also supported with RTT. SWO output also creates another section. RTT is the better choice on parts where the SWO pin is unavailable or contended, and having both in one tool means the choice is per board rather than per project.

The debugger views and the things that trip people up

Beyond tracing, the extension adds a set of views to VS Code. There is a Cortex Core Register Viewer integrated into the Variables window since version 1.2, with the caveat that in some cases the st-util GDB server can report incomplete or incorrect registers, so there may be issues there. There is disassembly of source code along with instruction level breakpoints and stepping, and the actual disassembly window is provided and managed by VS Code rather than by the extension. Globals and static scopes appear in the variables view, and there is a Live Watch feature with supported GDB servers, tested with OpenOCD, J-Link, and ST-Link so far, since version 1.6.

RTOS thread support in the call stack window is available with J-Link, OpenOCD, and pyOCD, with the RTOS support depending on the GDB server. The warning that comes with it is the one to internalise: as a general rule do not try to use stepping instructions before the scheduler of your RTOS has started, because in many cases this tends to crash the GDB servers or leave them in an inconsistent state.

That is a real footgun. Stepping through a scheduler before it starts can leave a GDB server wedged, and the failure looks like a driver problem rather than a stepping problem.

Multi-core and multi-session debugging is supported, and there is initial support for Rust code, with most functionality working and issues invited to be reported. The extension also uses a set of sibling extensions under the mcu-debug organisation for various front-end services, and the README is explicit that this content was refactored out of this extension to make it work with other debuggers and with browsers. The highlights are a Memory Viewer, an RTOS viewer, and a Peripheral, or SVD, Viewer. VS Code should offer to install them, and an Extension Pack is mentioned as a future possibility.

The toolchain you have to bring yourself

The installation requirements are the part that determines whether this works on your machine, and they are stated as a list rather than a single install step.

You need the ARM GCC Toolchain, which provides arm-none-eabi-gdb and related tools. Then you need at least one of the GDB servers, and the list of options is where the practical differences lie. J-Link Software Tools provides the J-Link GDB Server. OpenOCD provides a GDB server that can be used with a number of debuggers, with two important notes: if a chip vendor ships its own OpenOCD version, use nothing but that, and on macOS do not use the default version of OpenOCD provided by homebrew, because it is not compatible with releases V0.2.4 and newer, and you can either install from source using homebrew with brew install open-ocd --HEAD, or use the packages from the xPack releases, which will also work. Some Linux versions and Windows may also need a more up-to-date version of OpenOCD from the xPack releases.

The remaining options are Texane's st-util GDB server, which only supports ST-Link debug probes, the ST-LINK GDB server packaged with STM32CubeIDE, and pyOCD, which supports the CMSIS-DAP debugger on a number of mbed boards, and the Black Magic Probe.

The ST-LINK case is worth a note because it is the one where the extension does work for you. The ST-LINK GDB server is packaged with STM32CubeIDE, which must be installed, and the location of the STM32CubeIDE and related tools is automatically resolved but can also be overridden using the armToolchainPath, stm32cubeprogrammer, and serverpath configuration settings.

The configuration surface is the launch.json, and the debug_attributes.md file in the repository is a summary of all the properties available there. The extension is described as highly configurable, and the wiki is the usage documentation, which the README acknowledges needs some help from the community.

Live Watch, and the refresh rate that matters

Live Watch is a feature worth understanding on its own, because the configuration in the package manifest explains a behaviour that otherwise looks like a bug.

The cortex-debug.liveWatchRefreshRate setting defaults to 300 milliseconds, and its description spells out the reasoning. The GUI refresh frequency is in milliseconds, your sample rate can be much faster than the refresh rate, and the VS Code UI cannot handle high refresh rates, so your Live Watch window will look frozen. The documentation does not recommend going below 250 milliseconds as it will not be legible anyway, and anything below 200 milliseconds did not work at all for the maintainers.

The setting accepts a number with a minimum of 100 and a maximum of 5000, and a multipleOf of 1.

So the rule of thumb is that the plotted data can be sampled far faster than the window updates, and the window is a decimated view rather than a complete record. If you need every sample, you are reading the wrong output, and the setting range tells you that below 200 milliseconds the extension cannot keep up at all rather than merely being slow.

The other debugger-level setting is cortex-debug.variableUseNaturalFormat, which defaults to true and controls whether variables are displayed in their natural format as specified by ARM, hex otherwise. That default matters on Cortex-M, where a plain integer and a pointer can look identical in hex.

The extension activates on two events, onDebugResolve for cortex-debug and onStartupFinished, and its category in the marketplace is Debuggers.

Editorial conclusion

Adopt Cortex-Debug if you develop firmware for Cortex-M and want the VS Code debugging experience with trace decoding and ITM graphing on top of a vendor GDB server. Do not adopt it if you are on a vendor toolchain that already integrates well, or if you need a fully vendor-neutral stack, since the extension deliberately leans on the GDB servers the vendors ship. Verify first that your chip's GDB server is one of the supported list, and that your ARM toolchain provides arm-none-eabi-gdb.

Frequently asked questions

What does the Cortex-Debug extension need to debug a Cortex-M board?

The ARM GCC Toolchain, which provides arm-none-eabi-gdb and related tools, plus at least one GDB server: J-Link Software Tools, OpenOCD, Texane's st-util, the ST-LINK GDB server from STM32CubeIDE, pyOCD, or the Black Magic Probe. The extension drives the server rather than the hardware itself.

Does Cortex-Debug work on non ARM devices?

The README says the extension name cannot be changed due to VSCode Marketplace rules, but it can be used by non Cortex-M devices and non ARM devices, and people have reported using it with Cortex-R and Cortex-A, Xtensa, RISC-V, and even x86, with the caveat that your mileage may vary.

How do I get pre-release versions of Cortex-Debug?

The extension uses the pre-release versioning system specified by Microsoft, and you can enable pre-releases within VS Code for this extension to automatically receive them. By default pre-releases are disabled, and the convention is that an odd minor version means a pre-release.

What trace features does Cortex-Debug support?

SWO decoding of console text output and binary data, including signed and unsigned 32-bit integers, Q16.16 fixed point integers, and single precision floating point values, with live graphing of decoded ITM data and support for custom JavaScript ITM decoders. SEGGER RTT is also supported over OpenOCD and J-Link with the same feature set.

Why does my Cortex-Debug Live Watch window look frozen?

The liveWatchRefreshRate setting defaults to 300 milliseconds, and the documentation explains that the VS Code UI cannot handle high refresh rates, so the window looks frozen even though your sample rate is much faster. It recommends not going below 250 milliseconds, and notes that anything below 200 milliseconds did not work at all.

Official sources

  1. Issues
  2. License: MIT
  3. Marus/cortex-debug on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/marus-cortex-debug.svg)](https://hysenlabs.com/projects/marus-cortex-debug)