====== ARM hardware debugging ======
{{template>:project:infobox|
name=ARM devboard debugging|
image=armpowered.png?200|
sw=-|
hw=-|
founder=[[user:abyssal]]|
interested=-|
status=active
}}
~~META:
status = active
&relation firstimage = :project:armpowered.png
~~
===== Introduction =====
This project was originally aimed at debugging Stellaris Launchpad board (ARM Cortex M4F), but can be applied to ARM-related and OpenOCD-supported devices as well. There is also some information on using external hardware JTAG debuggers.
===== Links =====
* [[http://fabhack.com/doc/stellaris|Quick steps to setup Stellaris Launchpad]] - quick setup of StellarisWare, toolchain; should be enough to compile most basic examples
* [[https://launchpad.net/gcc-arm-embedded|Recommended toolchain]] - note: be **extremely sure** to "make clean all" in StellarisWare directory (including hardware library, you'll sidestep linker issues)
* [[http://e2e.ti.com/support/microcontrollers/stellaris_arm/f/471/t/44452.aspx|HOWTO make malloc and _sbrk work with newlib]] - there's noone or nothing to clear .bss and initialize data sections for you
* [[http://www.ti.com.cn/general/cn/docs/lit/getliterature.tsp?literatureNumber=spma043&fileType=pdf|Diagnosing Software Faults in Stellaris Microcontrollers]] - how to diagnose what happened when your program ends up in hard fault (e.g. precise bus error, imprecise bus error)
* [[http://www.ti.com/lit/ug/spmu289a/spmu289a.pdf|Stellaris LM4F120 LaunchPad Evaluation Board]] - the short manual with pinout
* [[http://www.ti.com/lit/ds/spms351/spms351.pdf|LM4F120H5QR datasheet]] - the long //LM4F120H5QR// manual (note: //LM4F120H5QR// is the same as //TM4C1233H6PM//)
* [[http://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readings/ARMv7-M_ARM.pdf|ARM v7 Architecture Manual]] - (not-so-great) instruction reference
* [[https://github.com/utzig/lm4tools|lm4tools]] - tools for flashing and manipulating Tiva/Stellaris Launchpad
* [[https://github.com/libopencm3/libopencm3|libopencm3]] - library for various functions integrated on common ARM processors
* [[https://github.com/libopencm3/libopencm3-examples|Examples to go with libopencm3]]
* [[http://www.riffbox.org/category/riff-jtag-features/ | RIFF JTAG]] - "Big" JTAG for phone/tablet-like processors ARM7/ARM9/ARM11, Cortex A8/A9/15 - unfortunately not free software and Windows only
* [[http://www.tincantools.com/JTAG/Flyswatter.html | Flyswatter ]] - ARM + MIPS JTAG compatible with OpenOCD
* [[http://techwithdave.blogspot.com/2013/07/openocd-ft2232h-based-jtag-adapters.html | OpenOCD FT2232H based JTAG Adapter ]] - DIY JTAG based on FT2232H mini module
====== OpenOCD debugger + Qt Creator =====
OpenOCD is on-chip-debugger project that allows one to debug code with a GDB-machine-interface frontend - like command-line GDB itself, Qt Creator or Eclipse.
===== Building =====
Compilation for Stellaris Launchpad, required version of openocd >= 0.7.0 ([[http://processors.wiki.ti.com/index.php/Stellaris_Launchpad_with_OpenOCD_and_Linux#Run_OpenOCD|TI link for reference]]):
./configure --enable-maintainer-mode --enable-stlink --enable-ti-icdi
Add the usual "--prefix" before "make" and "make install", just keep it somewhere in $PATH. You may add multiple boards with ''--enable-XXXX'', like J-Link or Buspirate support. Starting with version 0.8.0 OpenOCD seems to enable all supported adapters by default, so there's no need to specify them.
===== Udev rules for debugger devices =====
If you haven't done so yet, create a rule file in ''/etc/udev/rules.d/'', otherwise openocd won't work for non-root users.
Example of ''/etc/udev/rules.d/51-arm-development.rules'', substitute //your_username// for the username openocd should run under:
#Stellaris/Tiva Launchpad ICDI
SUBSYSTEM=="usb", ATTR{idVendor}=="1cbe", ATTR{idProduct}=="00fd", MODE="0600", OWNER="your_username"
#ST-Link/v2
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", MODE="0600", OWNER="your_username"
#Segger J-Link
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", ATTR{idProduct}=="0101", MODE="0600", OWNER="your_username"
===== Connecting OpenOCD to Qt Creator =====
In one terminal, connect to on-chip-debugger (modify the path for configuration file depending on where you installed OpenOCD):
openocd --file ~/sat/share/openocd/scripts/board/ek-lm4f120xl.cfg
If you're using external JTAG, you may have to specify it as interface for openocd, following example shows usage for ST-Link/v2 JTAG connected to STM32F4 microcontroller:
openocd -f interface/stlink-v2.cfg -f target/stm32f4x_stlink.cfg
Now, from running Qt Creator, select from main menu **Debug-Start Debugging-Attach To Remote Debug Server**. Make sure to fill out //Debugger// to //arm-none-eabi-gdb// pointing to your toolchain's GDB debugger. Local executable should point at compiled ELF executable. Host:port combo will default to **localhost:3333**.
{{ :project:qt_creator_01.png?nolink |}}
Select **Window-Views-Debugger Log**.
Write three commads to the debugger log (this could be likely automated using the startup script option):
monitor reset halt
load
monitor reset init
The //monitor reset halt// will halt execution, the //load// command will load your ELF binary, //monitor reset init// will restore program to beginning. Resume execution (F5 key by default) to run the program. You can e.g. set breakpoints now or pause execution:
{{ :project:qt_creator_03.png?800 |}}
==== Qt Creator 3 requires GDB with Python scripting support ====
If you get error message from Qt Creator that GDB does not support Python scripting, you'll need to recompile GDB with Python support. [[https://www.gnu.org/software/gdb/download/|Download GDB]], configure it with:
./configure --target=arm-none-eabi --with-python
Qt Creator 3 has also a bit different dialogs, you'll need to point Qt Creator to the ARM GCC and GDB in **Tools->Options->Build&Run** by creating a new "kit" where you specify path to ''arm-none-eabi-gcc'' compiler and ''arm-none-eabi-gdb'' debugger.
===== JTAG vs SWD interface for debugging with external HW debugger =====
SWD (Serial Wire Debug) is a newer HW debug interface, using only 2 pins (SWDIO and SWCLK) instead of the 5-pin JTAG. SWD should be [[http://www.arm.com/products/system-ip/debug-trace/coresight-soc-components/serial-wire-debug.php | compatible with all ARM processors]]. The SWDIO and SWCLK pins are overlaid on the TMS and TCK pins of original JTAG header.
From OpenOCD's point of view, the physical connection doesn't matter.
===== Breakpoints and stepping =====
Breakpoints should work as usual, just don't forget "-g" flag and use no optimization "-O0" with gcc CFLAGS (last -O//N// flag "wins").
==== Caveats - SIGTRAP, long "step over" delay ====
If you are getting "SIGTRAP" shown from Qt Creator, **delete old breakpoints** and restart the program anew - reset or physically disconnect Stellaris Launchpad.
If "step over" is taking way too long (tens of seconds or minutes), it may mean that you've tried to step over a cycle or an expanded macro. Temporary breakpoint is much faster. Nevertheless, you may watch console output of openocd to see that the program is actually running, showing the PC register and waiting the breakpoint to hit.
==== Hard fault interrupt encountered, possibly due to optimization (FaultISR) ====
This section briefly covers how to find out why your code ended in FaultISR - which is usually the default fault handler set in StellarisWare projects. Follow [[http://www.ti.com.cn/general/cn/docs/lit/getliterature.tsp?literatureNumber=spma043&fileType=pdf|Diagnosing Software Faults in Stellaris Microcontrollers]].
=== Example showing Imprecise bus fault ===
How to trigger an ''IMPRE'' fault (imprecise bus error) we'll show as an example. Look at ''blinky.c'' from StellarisWare, there is a //"seemingly unnecessary line"// with assignment to the ulLoop variable in the main() method:
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
ulLoop = SYSCTL_RCGC2_R; // <--- !!! if commented out, may cause imprecise bus error with gcc's -O2 optimization !!!
//
// Enable the GPIO pin for the LED (PF3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTF_DIR_R = 0x08;
GPIO_PORTF_DEN_R = 0x08;
Try commenting out the line with assignment to ulLoop, compile with -O2 -g (e.g. add ''CFLAGSgcc=-O2 -g'') to Makefile. If you used the same toolchain (linked above as "recommended toolchain"), nothing will blink. When you attach using OpenOCD, you'll see that you've ended up in **FaultISR**.
===== Getting code completion working for StellarisWare, DriverLib, UsbLib =====
Easiest way is to have StellarisWare open as project. From **File-New File or Project**, select **Import existing project**, then select StellarisWare directory. In the second step where the dialog asks you to check subdirectories to import, it's enough to select just **driverlib**', **inc**, **usblib** and **utils**.
The other option would be adding path to the relevant include files (see Project tab). You might have to explicitly define some of the make macros like ''-DTARGET_IS_BLIZZARD_RA1'' under the Project tab to get ''ROM_'' and ''MAP_'' prefixed functions to resolve correctly, but it was not necessary in my case.
====== Stellaris Launchpad as simple logic analyzer ======
Given the clock speed of Stellaris Launchpad, it's fairly fast enough for snapping signals. With a bit of proper synchronization, can be used as a [[http://hackaday.com/2013/01/27/turning-the-stellaris-launchpad-into-a-logic-analyzer/|logic analyzer with short memory]] (alternatively [[http://www.fischl.de/arm/sllogiclogger_logic_analyser_for_stellaris_launchpad/sllogiclogger.2012-12-24.tar.gz|direct download link for the tar.gz]]). In the comments towards the end, there is a version that uses more than 16 kB RAM, meaning longer time interval can be sampled.
The code turns Stellaris into SUMP-protocol compatible device, you can use [[http://www.lxtreme.nl/ols/|OLS Logic Sniffer client]] to read from it. Any time a GPIO value on PORTB[0..7] changes, the capture starts. Note: **PB0 and PB1 are limited to 3.6 V!** All other pins of PORTB are 5 V tolerant.
First flash the ''sllogiclogger.bin'' image onto Stellaris you'll use for measurement. Then copy over the config file ''ols.profile-SLLogicLogger.cfg'' from sllogiclogger tarball to ''ols-0.9.6.1/plugins'' directory (or whatever your version of OLS is).
Sample showing sllogiclogger for debugging [[http://www.atmel.com/devices/atsha204.aspx|ATSHA204]] single-wire communication. One Stellaris controls the ATSHA204, the other Stellaris serves as sllogiclogger. PB6 and PB7 are used to read from, as the OLS screen shows.
{{ :project:stellaris_logic_analyzer.jpg?nolink |}}
{{ :project:ols_analyzer_uart_02.png?nolink |}}
You might want to change the line ols.profile-SLLogicLogger.cfg containing ''device.samplerates'' to make your measurement more precise. Since sllogiclogger uses raw for() cycle without interrupts and DMA, the actual sampling frequency highly depends on compiler and flags used when you compile the sllogiclogger.
For instance, I didn't need 10 MHz, I was okay with 1 MHz but longer captute. So after some measurements I've found out that using 1236000 Hz for ''device.samplerates'' and changing sllogiclogger.c divider ''SYSCTL_SYSDIV_27'' in ''ROM_SysCtlClockSet'' call, it measures fairly accurately when it's compiled with -O2 flag with the recommended toolchain mentioned above.
Though for any more serious work, it's best to use a real logic analyzer, like [[http://dangerousprototypes.com/docs/Open_Bench_Logic_Sniffer|Open Bench Logic Sniffer]].
====== Open Bench Logic Sniffer with OLS client ======
First of all, **it is absolely substantial to flash both FPGA and PIC firmware** of Open Bench sniffer to make it work reliably with OLS client - see [[http://dangerousprototypes.com/docs/Open_Bench_Logic_Sniffer#Updates|updates]]. Otherwise the triggers may not work reliably. Note that the flashing new FPGA/PIC firmware may not work the first time, try multiple attempts (also, Linux OLS updater depends on old libusb shared libraries). Links for quickstart and using triggers:
* [[http://dangerousprototypes.com/docs/Logic_Sniffer_quick_start_guide|Quick start]]
* [[http://dangerousprototypes.com/docs/Logic_Sniffer_101|Logic Sniffer 101]]
* [[http://dangerousprototypes.com/docs/Logic_Sniffer_102|Logic Sniffer 102]]
* [[http://dangerousprototypes.com/docs/Logic_Sniffer_103|Logic Sniffer 103]]
Udev rules file for fast copy-pasta (last line should sidestep potential issues with ''modem-manager''):
#File /etc/udev/rules.d/55-ols.rules
#Rules for Open Bench Logic Sniffer
# Creates nice /dev/OpenLogicSniffer symlink writable even for users not part of dialout group
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fc92", MODE="0666", SYMLINK+="OpenLogicSniffer"
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fc92", ENV{ID_MM_DEVICE_IGNORE}="1"
===== PureJavacomm exceptions on Linux kernel 3.7+ for non-root users =====
If you are unable to capture data under non-root user despite having correctly set [[http://dangerousprototypes.com/docs/Logic_Sniffer_quick_start_guide|udev rules]], you'll need PureJavacomm update. The exception message is:
java.lang.IllegalStateException: JTermios call returned -1 at class jtermios.JTermios JTermiosLogging line 489
Symptoms detailed:
* [[https://github.com/jawi/ols/issues/133|Broken on kernel 3.7]] - strace shows ''ioctl(TIOCSSERIAL, ...)'' call failing
* [[https://github.com/jawi/ols/issues/159|Weird user permission problem using client on Linux]]
Quick fix:
The fix for PureJavacomm is described in issues #133 and #159. Snapshot for OLS 0.9.7 contains the fix:
* [[https://drone.io/jawi/OLS-client/files|OLS client development downloads]]
===== Sample photo: Open Bench Logic Sniffer debugging ATSHA204 on Stellaris Launchpad =====
Here is Open Bench Logic Sniffer showing communication from ATSHA204. Note that channel 0 contains different single-wire (not 1-wire!) communication for RX and TX separately as specified by ATSHA204 docs (203.4 and 166.6 kbaud). OLS screenshot comes from OLS 0.9.7 development snapshot.
{{ :project:ols_stellaris.jpg?nolink |}}
{{ :project:ols_analyzer_uart_03.png?800 |}}
====== J-Link external JTAG with OpenOCD ======
===== Example: debugging Proxmark (Atmel AT91SAM7S256) =====
OpenOCD has interface file for J-link in ''interface/jlink.cfg'' directory and ''target/at91sam7x256.cfg'' for the chip, but both require some changes:
* setting JTAG speed
* disabling ''gdb_memory_map'' (we'd need to send correct memory map to tell which memory areas belong to flash and should be protected)
* requesting hard breakpoints (for some reason soft breakpoints don't work, it seems to have to be related to missing memory map)
==== OpenOCD config file ===
Create a file name ''proxmark3-jlink.cfg'' with this content:
{{:project:proxmark3-jlink.zip|}}
(Sorry I had to put it here zipped as it couldn't be uploaded as .cfg and neither put as file/code into the page - it was impossible to escape)
==== Putting it together ===
The "load" command was not working correctly for me, so I had to use the ''flasher'' utility to flash the OS image (''./client/flasher /dev/ttyACM0 ./armsrc/obj/osimage.elf''). Alternatively it's possible to use the J-link JTAG to flash image (see below).
As usual, run openocd first:
openocd -f proxmark3-jlink.cfg
Then GDB in another terminal - ''arm-none-eabi-gdb armsrc/obj/fullimage.elf''. It's recommended that you recompile code with debugging symbols enabled. In gdb shell, connect to gdb server and try a breakpoint on some simple function:
target extended-remote :3333
continue
## press Ctrl-C to break ##
backtrace
## you should see some valid backtrace now
break 'SendVersion'
continue
When you run proxmark client (''./client/proxmark3 /dev/ttyACM0''), give it ''hw version'' command. GDB should now break at the SendVersion breakpoint you've set before.
===== Example: Unbricking (restoring) Proxmark bootloader =====
When bootloader gets overwritten into unusable state, this method can be used to overwrite flash sectors with fresh correct bootloader. The config file below is very similar to the one used for code debugging (I guess that one could work too, not sure about the memory map enabling).
{{:project:proxmark-jlink-reflash.zip|}}
Run openocd in one terminal:
openocd -f proxmark3-jlink-reflash.cfg
In another terminal, use netcat or telnet to connect to port 4444 where openocd's shell runs:
nc localhost 4444
Give these commands to openocd:
halt
flash erase_sector 0 0 last
flash write_image /full/path/to/bootrom.elf 0 elf
The code halts processor, erases bootloader sectors, then writes bootloader from ''/path/to/booloader.elf''. After power cycling the bootloader should be working if the elf file is correct.
If you receiving errors:
Info : TAP autoX.tap does not have IDCODE
.(some more info)
Warn : Unexpected idcode after end of chain: XY 0x00000000
.(some more warinings)
Error: auto0.tap: IR capture error; saw 0x0000 not 0x0001
It's because your CPU has locked flash/JTAG.
To solve this connect pin 55(ERASE) of CPU to 3.3V for at least 0.5sec. It will trigger erase of flash content and enable JTAG.
This is happening mostly on cheap clones of proxmark3 Easy.
To debug Proxmark on newer OpenOCD >= 0.10.0, you may set fast memory access and fast DCC downloads:
openocd -c "adapter_khz 4000" -f interface/jlink.cfg -c "gdb_memory_map disable" -f target/at91sam7x256.cfg -c "init; arm7_9 fast_memory_access enable; arm7_9 dcc_downloads enable"
Seems that flashing bootloader may not be enough, flash bootloader.elf and fullimage.elf from the same build in a single session (e.g. use ''file'' command in gdb), since mixing different branches may still result in bricked proxmark. Some bootloaders can't load fullimages built from other branches.
===== J-link connected to Proxmark =====
{{ :project:proxmark-jlink.jpg?800 | }}
===== SystemView for J-link - visualization of interrupts or other functions =====
There is an instrumentation possible with changes to code to show how your functions and interrupts behave - [[https://wiki.segger.com/Use_SystemView_without_RTOS | sample code]]
Here is an example showing "tail chaining" of interrupts where interrupts are behind one another, and also "late arriving", where Systick interrupts USB interrupt (marked as IST #93 starting at position 2195):
{{:project:arm_debugging:systemview_20200318_113539.png?800|}}
If you add extra functions, it may measure your functions as well:
{{:project:arm_debugging:systemview_20200318_100652.png?800|}}
As a side note, ST-link on STM32 discovery boards can be reflashed to JLink (works only on discovery boards, not on separate ST-links).
===== ARM ETM trace - recording executed instructions =====
ARM processors (Cortex M1+ and others) have built-in a nifty feature that you can record all instructions executed. This requires quite costly hardware (expect 2000 EUR price - JTrace, Lauterbach and uLink), but it can be handy in debugging DMA and interrupts.
An example ETM trace:
{{:project:arm_debugging:ozone_error_shutdown_highlighted.png?800|}}
===== ARM ITM trace - recording samples of executed instructions, interrupts =====
You can get code profile like this with ITM (screenshow from ''orbtop''):
{{:project:arm_debugging:orbtop_trezor_lots_of_segwit_inputs.png|}}
To get this working, [[https://github.com/hiviah/ITM-howto-JLink-STLink|follow this howto]]. It shows steps to be used with JLink/JTrace or STLink to get it moving.
====== Flyswatter connected to Proxmark ======
Flyswatter needs TDI pin connected, otherwise it won't work. SWD protocol seems not to work with Flyswatter. You can use board config from above section with:
openocd -f interface/ftdi/flyswatter.cfg -f board/proxmark3-jlink.cfg
===== Flyswatter debugging Proxmark =====
{{ :project:flyswatter-proxmark.jpg?800 | }}
====== FTDI C232HM-DDHSL-0 cable ======
The [[http://www.ftdichip.com/Products/Cables/USBMPSSE.htm | FTDI C232HM-DDHSL-0 cable]]([[http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_C232HM_MPSSE_CABLE.pdf | datasheet]]) is a handy portable cable that combines UART, JTAG, I2C and SPI. UART works out-of-the-box, SPI and I2C are supported through [[https://code.google.com/p/libmpsse/ | libmpsse]]. JTAG is supported in OpenOCD, use this config (save it as ''interface/ftdi/c232hm.cfg'' under scripts). It's actually the same hardware as [[https://digilentinc.com/Products/Detail.cfm?NavPath=2,395,1053&Prod=JTAG-SMT2 | Digilent SMT2 JTAG]].
#
# FTDI C232HM-DDHSL-0
#
# http://www.ftdichip.com/Products/Cables/USBMPSSE.htm
#
# Config is based on tumpa-lite.cfg
#
interface ftdi
adapter_khz 12000
#gdb_memory_map disable
ftdi_vid_pid 0x0403 0x6014
ftdi_layout_init 0x0038 0x087b
# ??? is this correct - connect nTRST to grey cable, GPIOL0
#ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010
# connect to purple cable, GPIOL1 (is this correct? seems to work with side effects)
#ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020
The only strange this is that the FTDI cable is missing nSRST signal, so you can't reset the processor via ''monitor reset halt''. Connecting nSRST to GPIO pin and using nSRST in config as noted above will allow you to reset via ''monitor reset halt''.
===== UrJTAG =====
UrJTAG doesn't have named driver for this, but you can use Flyswatter, JTAGkey, Signalyzer or Turtelizer2 explicitly specifying USB PID, e.g.:
jtag> cable Flyswatter pid=0x6014
Connected to libftdi driver.
jtag> bsdl path Downloads/
jtag> detect
IR length: 4
Chain length: 1
Device Id: 00111111000011110000111100001111 (0x3F0F0F0F)
* Filename: Downloads//AT91SAM7S256.bsd
Weird quirk: after using OpenOCD, UrJTAG won't detect anything with ''detect'' command unless you replug the FTDI cable.
====== Chipwhisperer + UFO target board + STLink v2 + STM32F4 ======
[[https://wiki.newae.com/CW1173_ChipWhisperer-Lite | Chipwhisperer]] with [[https://wiki.newae.com/CW308_UFO_Target | UFO target board]] installed with STM32F4. This method will work for other STM32Fx family MCUs.
The STM32F4 can be programmed via Chipwhisperer IDE (you need to use "slow" setting, otherwise it seems to fail) or STLink as usual with gdb+openocd.
There are few gotchas for [[https://wiki.newae.com/CW308T-STM32F | older versions of the STM32Fx target board, like the jumper for SHUNTL and SHUNTH (SH+ and SH-) on J16 for programming]]. Though using STLink is definitely a better idea as using the built-in programmer is insanely slow.
{{:project:arm_debugging:chipwhisperer_stlink_stm32f4.jpg?1000|}}
Example building the AES target program ''simpleserial-aes'':
make PLATFORM=CW308_STM32F4 CRYPTO_TARGET=TINYAES128C
===== Fix for Ubuntu 18.04's broken newlib and GDB =====
Ubuntu 18.04 since has broken newlib - ''error: /usr/lib/gcc/arm-none-eabi/6.3.1/../../../arm-none-eabi/lib/crt0.o: Conflicting CPU architectures 13/1''.
Fix can be seen [[https://github.com/bbcmicrobit/micropython/issues/514#issuecomment-404759614 | in this github issue comment]].
To fix it, download and install packages:
* https://packages.ubuntu.com/cosmic/all/libnewlib-dev/download
* https://packages.ubuntu.com/cosmic/all/libnewlib-arm-none-eabi/download
Install those two packages:
dpkg -i libnewlib-dev_3.0.0.20180802-2_all.deb libnewlib-arm-none-eabi_3.0.0.20180802-2_all.deb
You need to install GDB from sources, as the gdb-multiarch seems broken. See above for building gdb for ''arm-none-eabi'' with python.
===== Running OpenOCD and debugger =====
Run OpenOCD in one terminal, or use QtCreator setup mentioned above. There is option to use [[https://blog.jetbrains.com/clion/2017/12/clion-for-embedded-development-part-ii/ | CLion]]. QtCreator is great if you want free (free as in beer also LGPL) IDE, but CLion is better when it comes to code completion in C++11 and later, especially through templates that extend classes like smart pointers. Though for C code, both are about the same. Maybe QtCreator can be preferrable.
openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg
If you have different model, e.g. STM32F3 (or F2/F0), just change that parameter in openocd invocation, for F3 (the second file points to config in openocd installed configs):
openocd -f interface/stlink-v2.cfg -f target/stm32f3x.cfg
In another terminal, run gdb (modern gdb supports multiple architectures, you need gdb-multiarch or such package, but compiling latest version yourself might be preferrable) with target file, e.g. ''arm-none-eabi-gdb hardware/victims/firmware/simpleserial-aes.arm-stm32f4/simpleserial-aes-CW308_STM32F4.elf''. Note that the clock setting in Chipwhisperer IDE might influence the clocks in OpenOCD configs. So far GDB seems to handle it well on its own. If you are using CW308 UFO board, there is J3 switch to select clock. Unless you want to do something special with the clock, use "HS2/OUT" jumper option. [[https://wiki.newae.com/CW308_UFO_Target#Clock_Selection | Clock selection]] is important for glitching clock, for example.
GNU gdb (7.10-1ubuntu3+9) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hardware/victims/firmware/simpleserial-aes.arm-stm32f4/simpleserial-aes-CW308_STM32F4.elf...done.
(gdb) target extended-remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
(gdb) monitor reset halt
Unable to match requested speed 1000 kHz, using 950 kHz
Unable to match requested speed 1000 kHz, using 950 kHz
adapter speed: 950 kHz
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080014e4 msp: 0x20003000
(gdb) load
Loading section .isr_vector, size 0x188 lma 0x8000000
Loading section .text, size 0x140c lma 0x8000188
Loading section .rodata, size 0x24 lma 0x8001594
Loading section .init_array, size 0x4 lma 0x80015b8
Loading section .fini_array, size 0x4 lma 0x80015bc
Loading section .data, size 0x20c lma 0x80015c0
Start address 0x80014e4, load size 6092
Transfer rate: 14 KB/sec, 1015 bytes/write.
(gdb) monitor reset init
Unable to match requested speed 1000 kHz, using 950 kHz
Unable to match requested speed 1000 kHz, using 950 kHz
adapter speed: 950 kHz
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080014e4 msp: 0x20003000
Unable to match requested speed 8000 kHz, using 4000 kHz
Unable to match requested speed 8000 kHz, using 4000 kHz
adapter speed: 4000 kHz
(gdb) c
Continuing.
===== Side channels =====
There is a [[https://brmlab.cz/project/chipwhisperer/start | separate project for Chipwhisperer]] and its usage for side channels. Look there.
===== JTAG supplying external clock =====
It seems that when you desolder clocks (e.g. from crystal oscillator) the SWD/JTAG clock (SWCLK/TCK) can supply the clock to the chip which can be useful e.g. when you need glitch clock, but still would need operation via SWD/JTAG. Tested on [[https://brmlab.cz/project/chipwhisperer/start#glitching_stm32_external_board_through_ufo-board_interface | STM32F429 discovery board]].
Doesn't seem to work with Black Magic probe without clock.
===== Black Magic Probe =====
[[https://github.com/blacksphere/blackmagic/wiki | Black Magic Probe]] (BMP) a replacement either for STLink firmware or usable as firmware on various ARMs to debug other ARMs.
Pinout on the debug board is only findable in sources under src/platforms.
Interesting features:
1. you can catch hardware ARM interrupts, e.g. "monitor vector_catch enable mm" (catches memory faults)
2. SWD and JTAG boundary scan of devices
3. you can use multiple devices connected
Differences from OpenOCD+GDB:
1. you can't use OpenOCD flashing or other OpenOCD commands (this is since BMP created USB-UART device and not a network device)
2. commands used are different, e.g. BMP has "run"/"start" while OpenOCD+GDB has "monitor reset init"/"monitor reset halt"/"monitor reset", connecting to device is different (refer to BMP wiki)
BMP creates /dev/ttyACM* interface that can be used without OpenOCD as extended-remote target (see BMP wiki).
Some interesting features compared to old OpenOCD+gdb should be tracing support, but after discussions on the BMP discord channel it **doesn't fucking work** with BMP:
* https://github.com/blacksphere/blackmagic/wiki/Serial-Wire-Debug-TRACESWO-support (this shit doesn't work no matter what the docs say, confirmed from the main developer)
* https://github.com/orbcode/orbuculum (you need the specific FPGA to make this work, or spend time porting it to different FPGA
Note that you have to disable memory protections in order to read some memory (**set mem inaccessible-by-default off**), even then some parts that are accessible via STLink are not with BMP.
==== Building and flashing Black Magic Probe on STLink v2 device ====
In the build directory:
make PROBE_HOST=stlink ST_BOOTLOADER=1
Get the stlink-tool and build it in a directory different from blackmagic sources:
git clone https://github.com/jeanthom/stlink-tool
cd stlink-tool
git submodule init
git submodule update
make
Flash the built BMP with STLink bootloader (you may need to replug the STLink):
./stlink-tool /path/to/src/blackmagic.bin
After each replug of STLink, you need to run ''stlink-tool'' without arguments to activate it:
./stlink-tool
After this, ''/dev/ttyACM*'' appears. You can use script like this to a) symlink the devices and b) run the stlink-tool automatically. Automatic run means you can't upgrade until you disable it. Here are the udev rules:
# Black Magic Probe
# there are two connections, one for GDB and one for uart debugging
SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb"
SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg"
# Automatic running of stlink-tool, not recommended, uncomment following line and fill in the path to stlink-tool if you need it
#SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", ACTION=="add", RUN+="/stlink-tool"
Beware of ModemManager, sometimes even ignoring it in udev rules won't help (maybe since the device is changing USB VID:PID and descriptors? not sure)
==== Useful GDB script for better visualization ====
If you are reversing low-level assembler interface, catching interrupts, or doing some low-level work, this is a good interface for GDB: https://github.com/cyrus-and/gdb-dashboard
Qt Creator can still be used though, but you might need to send the **target extended-remote /dev/ttyACM0** or **target extended-remote /dev/ttyBmpGdb** manually.
Preview of the GDB dashboard:
{{:project:arm_debugging:screenshot_20191219_001842.png?800|}}
==== Invocation inside GDB ====
First of all, you need to use /dev/ttyACM (or the symlink /dev/ttyBmpGdb if you used udev rules above), secondly you need to scan for you target, then attach it and finally run/start/continue it.
>>> target extended-remote /dev/ttyBmpGdb
Remote debugging using /dev/ttyBmpGdb
>>> monitor help
General commands:
version -- Display firmware version info
help -- Display help for monitor commands
jtag_scan -- Scan JTAG chain for devices
swdp_scan -- Scan SW-DP for devices
targets -- Display list of available targets
morse -- Display morse error message
halt_timeout -- Timeout (ms) to wait until Cortex-M is halted: (Default 2000)
connect_srst -- Configure connect under SRST: (enable|disable)
hard_srst -- Force a pulse on the hard SRST line - disconnects target
traceswo -- Start trace capture, NRZ mode: (baudrate)
>>> monitor swdp_scan
Target voltage: unknown
Available Targets:
No. Att Driver
1 STM32F42x M3/M4
>>> attach 1
>>> monitor vector_catch enable mm ## example how to set breakpoint on memory fault interrupt
>>> continue
==== Reflashing BMP back STLink v2 (possibly may work with v2.1) ====
You either need to find the original STLink firmware somewhere (or have dumped it before) and use ''stlink-tool'' to flash it back or use [[https://www.st.com/en/development-tools/stsw-link007.html | STLink Upgrade Tool]]. If it doesn't find your device, replug it physically and try again.
Note on v2 vs v2.1 from BMP developer:
//To reflash ST-Link v2, un- and replug to get into the St bootloader. Stlinkv2-1 needs a warm reset to enter the bootloader, but mostly STLinkUpgrade.jar will not recognize the chip. Try with some old version of STLinkUpgrade.jar.//
//B.t.w,BMP with git can now run some things from the command line, when PC-hosted, e.g. "blackmagic_hosted file.bin" will erase and flash file.bin at 0x08000000 . PC-hosted is not fast, maybe [[https://github.com/blacksphere/blackmagic/issues/570 | #570]] can improve by using high level commands.//
==== Cheap Chinese STLink v2 clones ====
Some of them can be reflashed to BMP, some can't (stlink-tool reports error). There are more versions, so the pinout on the outside and also on the board depends on the specific clone type.
An example how to [[http://blog.linuxbits.io/2016/02/15/cheap-chinese-st-link-v-2-programmer-converted-to-black-magic-probe-debugger/ | use one cheap clone to flash other]]. The cloned STLink is STM32F1 and it has [[http://blog.linuxbits.io/wp-content/uploads/2016/02/P1160474_clipped2.jpg | SWD pins routed out on the board]]
Original STLink (flashed with BMP with ST bootloader) using to program BMP on the cheap clone (haven't yet figure out how to restore ST bootloader, since I don't have the executable image containing the bootloader):
{{:project:arm_debugging:stlink_clone_bmp.png|}}
==== BMP PC-hosted with BMP HW target ====
For BMP built with ''PROBE_HOST=pc-hosted'' you can connect to an external physical BMP with:
./src/blackmagic_hosted -s /dev/ttyACM0
It will create port 2000 listening for GDB connection and you can use the classic BMP commands like scan and attach:
>>> target extended-remote :2000
Remote debugging using :2000
>>> monitor swdp_scan
Target voltage: unknown
Available Targets:
No. Att Driver
1 STM32F1 medium density M3/M4
>>> attach 1
Attaching to program: blackmagic-stlink-v2/src/blackmagic, Remote target
0x0800effc in st_usbfs_ep_read_packet (dev=, addr=, buf=, len=) at ../common/st_usbfs_core.c:230
230 USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
==== BMP PC-hosted with unmodified STLink v2 target (requires firmware >= V2J32xx) ====
Upgrade STLink fw first with the STLinkUpgrade tool mentioned before.
With this firmware you can use external unmodified STLink with BMP (''PROBE_HOST=pc-stlinkv2''):
./src/blackmagic_stlinkv2
It will create port 2000 listening for GDB connection and you can use the classic BMP commands like scan and attach:
>>> target extended-remote :2000
Remote debugging using :2000
>>> monitor swdp_scan
Target voltage: unknown
Available Targets:
No. Att Driver
1 STM32F1 medium density M3/M4
>>> attach 1
Attaching to program: blackmagic-stlink-v2/src/blackmagic, Remote target
0x0800effc in st_usbfs_ep_read_packet (dev=, addr=, buf=, len=) at ../common/st_usbfs_core.c:230
230 USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
===== Other useful tools that are specific to STM32 chips =====
* [[https://www.st.com/en/development-tools/stm32cubemx.html | STM32CubeMX]] - GUI for designing MCU/board settings, shows you the options, pinout of chips, can generate code to set the configuration.
* [[https://www.st.com/en/development-tools/stm32cubeprog.html | STM32CubeProg]] - GUI/CLI programmer, can change things like read/write protect, option bytes, memory contents, etc. You need Oracle Java >= 8 for this, otherwise the GUI part won't work (use JAVA_HOME env var to set the Oracle java dir, then run the program). CLI seems to work without Oracle Java.
* [[https://www.st.com/en/development-tools/stsw-link007.html | STLink Upgrade Tool]] - upgrade for STLink. I think it's also part of STM32CubeMX