Arm none eabi gdb windows

Настройка Toolchain(а) для сборки артефактов под STM32. x86-64, Win, Eclipse, GCC, Make, GDB, ST-LinkV2

В этом тексте я расскажу какой путь проходят исходники с момента написания до момента исполнения на микроконтроллере и как сварить прошивку. Также прокопаю тему как настроить ToolChain из бесплатных утилит. В этом тексте я покажу на что следует обратить внимание при запуске первого проекта на ARM Cortex-M чипах. Этот текст, в сущности, пояснение того, что происходит под капотом большинства IDE (IAR, Keil, CodeComposerStudio и пр.). Можете читать это как курс молодого боевика бойца.

Что же мне потребуется накатить на свой NetTop для разработки под STM32?

Вот список утилит с которыми скорее всего предстоит столкнуться при разработке прошивок для чипов STM32.

Программа/Утилита

Назначение

STM32 ST-LINK Utility.exе 

GUI прошивальщик по SWD/JTAG

ST-LINK_CLI.exe

CLI прошивальщик по SWD/JTAG

Putty /TeraTerm/HTerm

Терминалы Serial порта

STM Studio

Отрисовывать графики переменных из ячеек RAM памяти

Cygwin

Набор Unix утилит для Windows

pdf reader

браузер PDF файлов с документацией

python

интерпретатор языка Python

Cppcheck

Статический анализатор кода

git-bash.exe

Система управления версиями исходных кодов + удобны Unix CLI терминал

WinMerge

Сравнение текстовых файлов с подсветкой

ST-LINK_gdbserver.exe

Отладочный сервер

WinRAR

распаковка архивов с документацией от вендора

GNU Tools ARM Embedded

Компилятор для ARM

Atollic TrueStudio

Набор утилит

Tor Browser

Web Browser для скачивания утилит и документации из санкционных территорий

Jenkins

Сервер сборки артефактов

hexdump /hexedit

просмотрщик бинарных файлов

grep

поиск подстрок в кодовой базе

find

поиск файла в файловой системе по регулярному выражению для его имени

STM32CubeMX

Генератор базового кода с примерами

clang format

автоматические выравнивание отступов

Notepad++

вспомогательный текстовый редактор специально для коммит сообщений

Eclipse IDE for C/C++ Developers 

текстовый редактор

Фаза 1. Установка текстового редактора

Так как любая программа это прежде всего текст, то надо установить какой-нибудь текстовый редактор.

Предлагаю Eclipse IDE for C/C++ Developers так как у него весьма удобные HotKeys. Для ускорения написания кода.

Плюс в Eclipse приятное синее выделение.

Еще Eclipse мгновенно запускается. Как по мне качество текстового редактора определяется тем как часто вам приходится пользоваться мышкой. В хорошем текстовом редакторе мышка вообще не нужна. Eclipse один из таких текстовых редакторов.

Установить Eclipse IDE for C/C++ Developers можно отсюда
https://www.eclipse.org/downloads/packages/

Установка заключается в распаковке скаченного архива в удобное место. В ОС Windows можно устанавливать Eclipse в корень диска С.

Программа запускается с помощью исполняемого файла eclipse.exe, который находится в распакованной папке. 

При первом запуске Eclipse надо выбрать рабочую папку (workspace). В этой папке Eclipse будет по умолчанию создавать проекты.

Настройка проекта в Eclipse

Настройки текстового редактора содержатся в файлах .project, .cproject. Важно снять галочку с пункта Makefile generation. В поле Build location прописать относительный путь к папке, которая содержит Makefile.

Настроить параллельную сборку чтобы ускорить цикл ToolChain(а). Это делается во вкладке Behavior

После этого инициировать сборки можно горячей клавишей Ctrl+B.

Фаза 2. Накатывание ToolChain(а) GCC под ARM для Cross компиляции на Win10

Нужен ToolChain: препроцессор (cpp), компилятор ASM(as), компилятор С (gcc),компилятор С++(g++), компоновщик(ld), отладчик(gdb). Нужны binutils(ы) для диагностики полученных артефактов(nm, size, readelf), архиватор статических библиотек(ar), и прочее. Это основные утилиты, которые и делают всю работу по превращению исходников (*.с, *.h) в артефакты (*.hex *.bin *.map *.elf *.out файлики).

ToolChain следует брать с официального сайта

https://developer.arm.com/downloads/-/gnu-rm#:~:text=The%20GNU%20Arm%20Embedded%20Toolchain,Arm%20Cortex%2DR%20processor%20families

.

Toolchain устанавливается как обычная win программа прямо из gcc-arm-none-eabi-10.3-2021.10-win32.exe файла

Проверка, что установилось. Вот полный комплект GCC ARM. Всего 32 утилиты.

Как же make файл узнает, что нужен именно этот toolchain? Ведь их может быть установлено несколько в разные папки. Ответ прост. Надо прописать адрес toolchain в переменной Path. А старый путь просто дропнуть.

и тут

Каждый свой шаг надо проверять. Как проверить, что терминал cmd находит ToolChain? Откройте cmd из любой папки и наберите arm-none-eabi-gcc.exe –v

Версия должна отобразиться в соответствии с версией скаченного дистрибутива. ToolChain может находится примерно по такому адресу:

C:\Program Files (x86)\GNU ARM Embedded Toolchain\10 2021.10\bin\

Фаза 3. Установка Windows Build Tools binaries (Make, cp, rm, echo, sh…)

Самый классический способ сборки программ на С(ях) это, конечно же, Make файлы. Не перестаю удивляться насколько элегантна сборка программ из make. В 1970е года когда появились утилита make программировали только настоящие ученые со степенями докторов наук. Тогда у школоты как сейчас банально не было персональных компьютеров из-за дороговизны DeskTop(ов). В 197x программировали по настоящему достойные люди. Поэтому и появились такие утилиты-шедевры как make, grep, find, sort и прочее. Благодаря Make файлам  можно управлять модульностью сборок программных компонентов по-полной. Мгновенно, одной строчкой включать и исключать сотни файлов одновременно для сотен сборок. Это даже не снилось таким GUI(ням) как IAR с Keil, где приходится протирать дыры в коврике для мышки, чтобы сделать то, что в make делается одной строчкой в *.mk файлике.

Сейчас среди российских программистов микроконтроллеров make файлами умеет пользоваться в лучшем случае один из шести. Остальные не могут слезть с иглы GUI-IDE. Сборка прошивок из make это считается высшим пилотаже программирования на С(ях).

Вот минимальный набор утилит для процессинга Make файлов.

Утилита

Назначение

make

build automation tool

sh

Unix shell interpreter

busybox

a software suite that provides several Unix utilities

echo

Echo the STRING(s) to standard output.

cp

Copy SOURCEs to DEST

mkdir

Create DIRECTORY

rm

Remove (unlink) FILEs

Где же мне взять универсальный Makefile для сборки много-файловых проектов? Самое простое это воспользоваться код-генератором STM32CubeMX и сгенерировать MakeFile проект.

Далее аккуратно раздербанить его под общую кодовую базу. Получается вот такой файл с правилами.

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
$(info Build  $(mkfile_path) )

BUILD_DIR = build

#@echo $(error SOURCES_C= $(SOURCES_C))
INCDIR := $(subst /cygdrive/c/,C:/, $(INCDIR))
#@echo $(error INCDIR=$(INCDIR))
SOURCES_C := $(subst /cygdrive/c/,C:/, $(SOURCES_C))
#@echo $(error SOURCES_C=$(SOURCES_C))
SOURCES_ASM := $(subst /cygdrive/c/,C:/, $(SOURCES_ASM))
LDSCRIPT := $(subst /cygdrive/c/,C:/, $(LDSCRIPT))
#@echo $(error SOURCES_ASM=$(SOURCES_ASM))

# binaries
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
  CC = $(GCC_PATH)/$(PREFIX)gcc
  AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
  CP = $(GCC_PATH)/$(PREFIX)objcopy
  SZ = $(GCC_PATH)/$(PREFIX)size
else
  CC = $(PREFIX)gcc
  AS = $(PREFIX)gcc -x assembler-with-cpp
  CP = $(PREFIX)objcopy
  SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
 
# CFLAGS
#https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
FPU = 
FPU += -mfpu=fpv4-sp-d16

FLOAT-ABI = -mfloat-abi=hard

MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

CSTANDARD = -std=c11

AS_DEFS = 

AS_INCLUDES = 
OPT += -Os
    
ifeq ($(DEBUG), Y)
    #@echo $(error DEBUG=$(DEBUG))
    CFLAGS += -g3 -gdwarf-2 -ggdb
endif

ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

CFLAGS += $(MCU) $(OPT) $(INCDIR) -Wall -fdata-sections -ffunction-sections $(CSTANDARD)


# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

# LDFLAGS

# libraries
LINKER_FLAGS += -Xlinker --gc-sections 
ifeq ($(MBR), Y)
    #@echo $(error MBR=$(MBR))
    LIBS += -lnosys
else
    LIBS += -lnosys 
    LINKER_FLAGS += -u _scanf_float
    LINKER_FLAGS += -u _printf_float
endif

ifeq ($(LIBC), Y)
    #@echo $(error LIBC=$(LIBC))
    LIBS += -lc
endif

ifeq ($(MATH), Y)
    #@echo $(error MATH=$(MATH))
    LIBS += -lm 
endif


#@echo $(error LDSCRIPT=$(LDSCRIPT))
LIBDIR = 

LDFLAGS += $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections $(LINKER_FLAGS)

# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin


# build the application
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES_C:.c=.o)))
vpath %.c $(sort $(dir $(SOURCES_C)))
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES_ASM:.S=.o)))
vpath %.S $(sort $(dir $(SOURCES_ASM)))

$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) 
	$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
	$(AS) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
	$(CC) $(OBJECTS) $(LDFLAGS) -o $@
	$(SZ) $@

$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(HEX) $< $@
	
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(BIN) $< $@	
	
$(BUILD_DIR):
	mkdir $@		

# clean up
clean:
	-rm -fR $(BUILD_DIR)
  
# dependencies
-include $(wildcard $(BUILD_DIR)/*.d)

# *** EOF ***

Вот так выглядит пример make файла для компонента независимого сторожевого таймера

$(info IWDG_MK_INC=$(IWDG_MK_INC) )
ifneq ($(IWDG_MK_INC),Y)
    IWDG_MK_INC=Y
    
    mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
    $(info Build  $(mkfile_path) )
    
    IWDG_DIR = $(WORKSPACE_LOC)bsp/bsp_stm32f4/iwdg
    #@echo $(error IWDG_DIR=$(IWDG_DIR))
    IWDG=Y
    INCDIR += -I$(IWDG_DIR)
    OPT += -DHAS_IWDG

    SOURCES_C += $(IWDG_DIR)/iwdg_drv.c

    ifeq ($(CLI),Y)
        ifeq ($(IWDG_COMMANDS),Y)
            OPT += -DHAS_IWDG_COMMANDS
            SOURCES_C += $(IWDG_DIR)/iwdg_commands.c
        endif
    endif
endif

А это MakeFile для конкретной сборки.

MK_PATH:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))
#@echo $(error MK_PATH=$(MK_PATH))
WORKSPACE_LOC:= $(MK_PATH)../../
INCDIR += -I$(MK_PATH)
INCDIR += -I$(WORKSPACE_LOC)

include $(MK_PATH)components.mk
include $(MK_PATH)cli_config.mk
include $(MK_PATH)diag_config.mk
include $(MK_PATH)test_config.mk
include $(WORKSPACE_LOC)code_base.mk
include $(WORKSPACE_LOC)rules.mk

В Makefile тоже можно делать Include guard подобно *.h файлам препроцессора.

$(info FILE_MK_INC=$(FILE_MK_INC))
ifneq ($(FILE_MK_INC),Y)
    FILE_MK_INC=Y
endif

И так далее. Для каждой сборки один Makefile и множество общих *.mk файлов.

Windows Build Tools binaries можно скачать по ссылке.

Можно скопировать утилиты Windows Build Tools  в папку:

C:\xpack-windows-build-tools-4.3.0-1\bin

Фаза 4. Подключить настройки компоновщика (Linker(а)). (*.ld файл)

После сборки *.с файлов образуются столько же *.o фалов. Их надо скомпоновать в один *.bin файл. Этим занимается утилита arm-none-eabi-ld.exe. Как и любой утилите нужен свой конфигурационный файл. Обычно это *.ld файл. Вот пример конфигурации компоновщика для сборки первичного загрузчика.


/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size  = 0x200; /* required amount of heap  */
_Min_Stack_Size = 0x900; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH

  
  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
    libnosys.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

Фаза 5. Подключить инициализацию окружения. Ассемблерный код.

До запуска функции main() происходит множество инфраструктурных действий:

  1. Выбрать вариант загрузки по двум Boot пинам (Flash 0x0000_0000, Flash 0x0800_0000, SRAM 0x2000_0000)

  2. Проинициализировать регистр указателя SP на начало стека первым qWord(ом) бинаря.

  3. Проинициализировать глобальные переменные в RAM данными из бинаря. (интервал rwdata).

  4. Обнулить неинициализированные переменные в RAM (интервал bss).

  5. Настроить ядро вычисление с плавающей точкой FPU.

  6. Прописать в регистры процессора местонахождение адресов обработчиков прерываний.

  7. Примонтировать, если нужно, внешнюю Off-Chip RAM память.

Всё это прописано в коде на Assembler в *.S файле. Который отрабатывает до запуска функции main(). Это например файл startup_stm32f413xx.S

Фаза 6. Нужны сорцы от Vendor(ов) чипа.

Чтобы можно было начать разрабатывать какое-то приложение и бизнес логику нужно целая куча системного софта. Это базовый софт или System Software. В его состав входит всяческая инициализация. Инициализация тактирования(TIM, RCC, RTC), интерфейсов (CAN, SPI, I2S, I2C, UART, USB, GPIO, SDIO, SAI, Ethernet), системных компонент (FLASH, SRAM, DMA, MPU, IWDG, RNG, FPU, NVIC), возможностей генерации (DAC, PWM). Это десятки тысяч строк кода. К счастью часть этого кода предоставляют нормальные вендоры чипов.

При разработке на STM32 у нас по сути два вендора: Компания ARM и Компания STMicroelectronic.

Компания ARM выпускает так называемый CMSIS(Common Microcontroller Software Interface Standard). Это С обертки для ASM команд под Cortex-M чипы. Так же *.ld файлики для компоновщика. Это скачивается с их сайта https://silver.arm.com/browse/CMSIS после регистрации

Компания STMicroelectonic выкатывает HAL Drivers — базовый системный софт для инициализации периферии микроконтроллера. Самое простое это установить их компанейский код генератор и STM32CubeMX по ссылке и сгенерировать проект.

STM32CubeMX сам скачает и сохранит сорцы базового кода в папку STM32F4xx_HAL_Driver. Только скачивать предстоит через Tor browser так как РФ у ST числится санкционной территорией. Вот список сорцов STM32F4xx_HAL_Driver от вендора:

Обратите внимание никаких статических библиотек (*.а) как у Texas Instruments. Чистые сорцы (*.c *.h файлики).

Фаза 7. Как скормить прошивку микроконтроллеру? 

Накатить прошивку на чип можно при помощи программатора ST-Link через интерфейс SWD/JTAG и утилиты STM32 ST-LINK Utility.exe. Программатор может быть встроен в отладочную плату от ST, как например в семействе Nucleo_f4XXXxx:

Если вы записываете Generic *.bin артефакт(приложение), то надо указать адрес начала бинарная в On-Chip Nor Flash памяти. Запись *.hex файлов безопаснее так как вам не надо явно указывать адрес начала прошивки. Прошивка это просто бинарный массив в файле. Текстовым редактором его не проанализируешь. Анализировать содержимое бинарных файлов (*.bin) можно консольной утилитой-переходником hexdump.exe. Даешь *.bin получаешь Hex Wall в *.txt

hexdump -C nucleo_f401re_gcc_m.bin > nucleo_f401re_gcc_m.txt

Стоит убедиться, что в первом qword всегда адрес из RAM (начало стека), а во втором qword всегда адрес из Flash (Reset_Handler).  Тогда прошивка не зависнет до запуска main().

GUI окно утилиты STM32 ST-LINK Utility.exe. Можно прописать прошивку по любому отступу.

Классическая ситуация: накатили прошивку и плата зависла. Не  мигает heartbeat LED. Как вариант может помочь пошаговая отладка.

Для пошаговой отладки потребуется обновление прошивки программатора ST-Link. Это можно выполнить прямо в утилите STM32 ST-LINK Utility.exe во вкладке ST-LINK:

С точки зрения DevOps(а) надо прошивать чипы из командной строки, Batch скриптом. Это легко автоматизировать. Вот скрипт автоматического обновления прошивки при помощи утилиты ST-LINK_CLI.exe

echo off
cls

set project_name=nucleo_f413zh_generic_gcc_d_m
set project_dir=%cd%
echo project_dir=%project_dir%
set artefact_hex=%project_dir%\build\%project_name%.hex
set FlashTool="C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe"
rem set Device= ID=0x463 SN=066CFF323535474B43013113 
set Device= 
set options= -c %Device% SWD freq=4000 HOTPLUG  LPM -P %artefact_hex% -V "after_programming" -Log -TVolt
call %FlashTool% %options%
rem Reset System
call %FlashTool% -Rst

 

Вот лог результата работы

Easy!
Прошивка из ST-LINK_CLI.exe эффективнее, поскольку использует драгоценный интерфейс USB-SWD, только тогда, когда это реально нужно, а не всегда как в GUI версия (STM32 ST-LINK Utility.exe).

Фаза 8. Установка Debug Server

Для пошаговой отладки надо установить GDB Server. Это утилита-переходник, которая с одной стороны допрашивает чип по SWD или JTAG, а с другой стороны обслуживает TCP сокет к которому подключится отладчик arm-none-eabi-gdb.exe к порту с номером 61234. 

Эту утилиту можно извлечь из набора утилит от Atollic TrueSTUDIO. Atollic TrueSTUDIO(R) for STM32 можно скачать с сайта ST.com.

 Надо зарегистрироваться на сайте st.com. Скачивать дистрибутив en.TrueSTUDIO_V9.3.exe.exe получится при помощи Tor Browser так как РФ у ST числится, как санкционная территория.

ST-LINK_gdbserver установлен в 

C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\Servers\ST-LINK_gdbserver\ST-LINK_gdbserver.exe

Нужно добавить в переменную Path путь к папке с утилитами binutils компилятора. В данном случае этот путь выглядит так:

C:\Program Files (x86)\GNU Tools ARM Embedded\5.4 2016q3\bin\

Опционально можно настроить конфигурацию отладчика в текстовом редакторе Eclipse во вкладке Run->External Tools->External Tools Configurations… или просто запустить GDB server (сервер отладки) вручную. Перейти в папку:

C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\Servers\ST-LINK_gdbserver

запустить скрипт  ST-LINK_gdbserver.bat.

C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\Servers\ST-LINK_gdbserver\ST-LINK_gdbserver.bat

Путь к отладочному серверу C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility следует прописать в переменную Path

Фаза 9. Настройка Debug конфигурации для конкретной сборки

Неудобство Eclipse по сравнению с тем же пресловутым IAR это то, что для каждой сборки приходится настраивать конфигурацию отладки. Однако в Eclipse можно нажать Ctrl+3 появится окно быстрого поиска

и набрать там Debug Configuration. Надо прописать путь к *.elf файлу.

На вкладке Debugger надо прописать путь к отладчику от ARM GCC

C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin\arm-none-eabi-gdb.exe

и прописать порт от сервера отладки localhost:61234

На вкладке Startup надо прописать, что следует поставить точку останова на функции main(). Можно поставить точку останова также на более ранних функциях Reset_Handler или SystemInit().

Перед началом пошаговой отладки надо запустить отладочный сервер . Достаточно просто запустить на исполнение скрипт ST-LINK_gdbserver.bat в папке 

C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\Servers\ST-LINK_gdbserver

Желательно из-под командной строки cmd, чтобы были видны логи отладочного сервера.

Для того чтобы выполнять пошаговую отладку нужно пересобрать артефакты с опциями компилятора

-g3 -gdwarf-2 -ggdb

Пошаговая отладка подсвечивается прямо в текстовом редакторе Eclipse зеленой строчкой. Это благодаря утилите arm-none-eabi-addr2line.exe. Текстовый редактор Eclipse сам парсит вывод addr2line и подсвечивает активный адрес в виде зелёной строчки в коде.

Во время пошаговой отладки светодиоды программатора ST-Link должны мигать зелено-красным цветом.

Блок-схема Toolchain(а)

Все вышесказанное можно представить в виде одной блок-схемы (Helicopter view) на одном единственном листочке. Такова общая канва.

Для нас исходниками являются файлы с расширениями *.ld, *.c, *.h, *.S, *.cproject, *.project, *.Makefile, *.mk , *.bat — их и надо подвергать версионному контролю в GIT.   Автогенеренными для нас являются файлы с расширениями *.o, *.bin, *.bak, *.hex, *.map, *.elf, *.out, *.d, *.a. Отгружать следует файлы *.bin, *.hex, *.map, *.elf. Это артефакты или конечный продукт работы программиста микроконтроллера. 

Также рекомендую пользоваться GIТ(ом) исключительно

из-под командной строки

. Так вы сможете обрабатывать вывод утилиты git легендарное утилитой grep. Можно делать вложенные grep поверх grep. Вот например так.

Если бы был аналог утилиты grep в материальном мире, то вы бы могли находить иголки в стоге сена, понимаете? Вам уже нравится утилита grep?

UART CLI Для отладки (или добавьте в прошивку гласность) 

Любая разработка начинается там, где есть возможность наблюдать за тем, что получилось после изменений. Поэтому вам понадобится интерфейс командной строки CLI для отладки софта и железа. Крайне желательно использовать раскраску логов, чтобы концентрировать внимание на ошибках (красный) и предупреждениях (желтый). Плюс появление цвета в консоли это признак того, что поток символов непрерывный так как коды цветов распарсились корректно. Своего рода контрольная сумма принятых данных. Да и вообще консольные логи должны выглядеть весело. Просматривать UART-CLI логи можно в утилите TeraTerm или PuTTY. Они точно понимают символы цветов.

Поэтому надо активировать свободный UART, написать в прошивке интерпретатор команд CLI для RunTime отладки по интерфейсу UART. CLI(шку) можно также инкапсулировать в любой полу или полнодуплексный интерфейс(LoRa, CAN, UART, RS485) или протокол (TCP/UDP). При наличии CLI для общения с гаджетом вам не нужно будет писать никакую GUI(ню) на QT, .Net или Python. Достаточно только общедоступных терминалов Serial порта как TeraTerm, PyTTY, Hercules. Это же успех!

Трюки для эффективной отладки прошивок

  • Всегда проверяйте адрес функции main(). Может случится, что техник записал Generiс *.bin в область памяти для Bootloader или наоборот. Прошивка должна проверять адрес функции main, что он лежит в нужном секторе On-Chip NorFlash(а).

  • Используйте файловую систему FlashFs. Это позволит уменьшить количество сборок, так как конфигурации будут в файловой системе.

  • Используйте HeartBeat LED. Так вы поймете, что прошивка зависла, если нет мигания.

  • Используйте GPIO+Oscilloscope+DMM для физической отладки быстрых процессов.

  • Разделяйте аппаратно-зависимый и аппаратно-независимый код. Аппаратно-независимый код тестируйте на LapTop(е).

  • Используйте серверы сборки (например Jenkins) для поддержания на плаву своих сборок. У вас всегда будет готовый артефакт для отгрузки. Плюс сразу будет видно какие сборки конфликтуют и оперативно принять меры по улучшению модульности.

  • Пишите свои загрузчики. Программатор может исчезнуть, сломаться. С загрузчиком вы обновите прошивку своего гаджета буквально по 3м проводам UART. Причем делайте первичный и вторичный загрузчик. Это позволит прописывать вторичный загрузчик по произвольному адресу.

  • Используйте интерфейс SWD/JTAG для пошаговой отладки и поиска причин зависаний.

  • Используйте утилиту STM Studio для построения графиков переменных по их адресу в ячейках RAM.

  • Покрывайте код модульными тестами (программные скрепы). Это лучший способ найти ошибку в коде, который затруднительно пройти пошаговой отладкой. Плюс тесты помогут безопасно делать перестройку (рефакторинг). Сегодня российское общество испытывает явный дефицит программных скреп.

Вывод

Существуют и другие ToolChain(ы) (IAR, Keil). Тут же я написал про бесплатный способ полноценно вести разработку и отладку на STM32. Однако если разработчик научится собирать код из make, то он перестанете быть рабом IDE с их периодическими зависаниями. Плюс можно сэкономить 3500 EUR не покупая проприетарный компилятор, который еще и не продадут из-за санкций.

Ссылки на похожие посты:

STM32 + CMSIS + STM32CubeIDE

ARM-ы для самых маленьких: тонкости компиляции и компоновщик

STM32 на MAC OS

Отладка STM32 в среде Eclipse+GCC

ARM-ы для самых маленьких: компоновка-2, прерывания и hello world!

STM32 + CMSIS + STM32CubeIDE

ARM-микроконтроллеры STM32F. Быстрый старт c STM32-Discovery

Развертывание среды разработки для STM32

STM32CubeMX — продвинутый генератор проектов для STM32

Eclipse для микроконтроллеров (STM32) + FreeRTOS Task Aware Debugge

Переход из online в offline IDE при программировании Nucleo-F401RE

Начинаем изучать Cortex-M на примере STM32

Программируем микроконтроллеры stm32 при помощи QtCreator

Настраиваем бесплатную сборку для написания и отладки программ под микроконтроллеры на основе ядра ARM под Windows 10

Tutorial: Makefile Projects with Eclipse

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы собираете артефакты прошивок из Make файлов?

Проголосовали 39 пользователей.

Воздержался 1 пользователь.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы пользуйтесь текстовым редактором Eclipse?

Проголосовали 42 пользователя.

Воздержался 1 пользователь.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы собираете артефакты для МК компилятором GCC?

Проголосовали 39 пользователей.

Воздержались 4 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы собираете прошивки в Windows?

Проголосовали 43 пользователя.

Воздержались 2 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы собираете артефакты прошивок из СMake файлов?

Проголосовал 41 пользователь.

Воздержался 1 пользователь.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы собираете прошивки из IDE IAR?

Проголосовали 43 пользователя.

Воздержался 1 пользователь.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы пользуйтесь пошаговой отладкой прошивок?

Проголосовали 43 пользователя.

Воздержался 1 пользователь.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы пользуйтесь отладкой прошивок через интерфейс командной строки?

Проголосовали 39 пользователей.

Воздержались 3 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы пользуйтесь сервером сборки (например Jenkins) для автоматической сборки артефактов?

Проголосовали 40 пользователей.

Воздержались 2 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы покрываете код прошивок модульными тестами?

Проголосовали 39 пользователей.

Воздержались 2 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы пользуйтесь системой контроля версий GIT?

Проголосовали 43 пользователя.

Воздержались 2 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Этот текст нанёс вам пользу?

Проголосовали 12 пользователей.

Воздержался 1 пользователь.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы обнаружили в тексте 3 пасхалки?

Проголосовали 10 пользователей.

Воздержался 1 пользователь.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Вы пользуйтесь утилитой grep?

Проголосовали 12 пользователей.

Воздержавшихся нет.

GDB, the GNU Project Debugger is a debugging tool provided with the GNU Compiler Collection (GCC). GDB allows you to stop and start a running program, examine its functioning, and make changes.

Contents

  • 1 GDB Support in OpenOCD
  • 2 Installing the CodeSourcery ARM Toolchain
  • 3 Starting GDB
  • 4 Connecting to OpenOCD
    • 4.1 Sending Commands to OpenOCD
    • 4.2 .gdbinit
    • 4.3 External Links

GDB Support in OpenOCD

The configure script provided with OpenOCD 0.5.0 already compiles OpenOCD to support the GDB debugger. If you have installed OpenOCD according to the guides on the Compiling OpenOCD page, your version of OpenOCD already supports GDB.

The -g flag tells the gcc compiler to build with GDB support. OpenOCD’s configure script already includes the -g flag.

You will need to download or compile a version of GDB that supports embedded devices. One such GDB build is provided with the CodeSourcery ARM toolchain.

Installing the CodeSourcery ARM Toolchain

CodeSourcery provides development tools for use with embedded devices, including a GCC cross-compiler and a GDB build for ARM targets. Download the latest version of the .bin installer from http://www.codesourcery.com/sgpp/lite/arm/portal/release1592. Direct link to the Windows installer is here.

Download and run the installer. You should see a loading bar followed by an installer GUI. The installer is fairly straightforward. This guide will assume that you choose the default option on each page.

Sourcery-install win.png

The installer installs the CodeSourcery toolchain, by default to C:\Program Files\CodeSourcery\Sourcery G++ Lite (or C:\Program Files (x86)\CodeSourcery\Sourcery G++ Lite on 64-bit Windows). It also adds this path to your system PATH variable so you can run arm-none-eabi-gdb and other tools from any directory.

Starting GDB

In the windows command console, type arm-none-eabi-gdb and press Enter. You can do this from any directory. If you’re unsure how to open the Windows command console, see Running OpenOCD on Windows. You can also run GDB directly from «Run» in the Start menu.

arm-none-eabi-gdb

Either way you should look like the image below, with a prompt reading (gdb) in place of the normal > command prompt.

Eabi-gdb startup win.png

Connecting to OpenOCD

Run OpenOCD as normal, as described in Running OpenOCD on Windows. To connect to OpenOCD, start GDB as above:

arm-none-eabi-gdb

OpenOCD listens for GDB connections on port 3333. In GDB, connect to OpenOCD by typing target remote localhost:3333. (In this guide if you see (gdb) at the beginning of a command, that means enter that line into the GDB command prompt. Don’t actually type the characters (gdb).)

(gdb) target remote localhost:3333

Before doing anything else, run reset init on the target. Use the monitor command to tell GDB to send the command to OpenOCD, like this:

(gdb) monitor reset init

Monitor reset init win.png

This is important. You need to do this while GDB is connected to the OpenOCD, or you won’t be able to halt or reset the target. If you don’t run monitor reset init, you will encounter errors like this:

Gdb packet err win.png

Sending Commands to OpenOCD

You can send commands to OpenOCD through GDB just like you can through a telnet connection. Type monitor, then the command, then enter. You can see a list of common OpenOCD commands here.

Gdb openocd commands win.png

You can use the Linux command cd to change the current working directory in GDB. This changes the current directory only for GDB, not for Linux; when you exit GDB, you will be back in the directory where you started.

To quit GDB, type quit.

.gdbinit

Instead of typing commands yourself every time you start GDB, you can create a script to always start GDB with the same series of commands. This script file is named .gdbinit. GDB looks for it in the current working directory.

You can use the script below to have GDB automatically connect to OpenOCD and run reset init on the target. Create a new folder on your C:\ drive called GDB_OpenOCD_init, and create a new text file in that folder. Copy the code below into the file:

echo Executing GDB with .gdbinit to connect to OpenOCD.\n
# Connect to OpenOCD
target remote localhost:3333
# Reset the target and call its init script
monitor reset init
# Halt the target. The init script should halt the target, but just in case
monitor halt

Save the file as .gdbinit and close it. Note that in Windows Explorer you can’t give a file a name that begins with a period. You will need to save it with the name .gdbinit from within a text editor. Alternatively, name the file gdbinit without a period and then rename it from the command line:

cd C:\GDB_OpenOCD_init
move gdbinit .gdbinit

To test the init script, start OpenOCD as normal. Then in the command line, navigate to C:\GDB_OpenOCD_init and run CodeSourcery GDB.

cd C:\GDB_OpenOCD_init
arm-none-eabi-gdb

You should see something like the image below. (In this image the target device is the Beagleboard. With different hardware the output of reset init will be different.)

Gdbinit win.png

External Links

GDB man page

The Embedded Rust Book

Windows

arm-none-eabi-gdb

ARM provides .exe installers for Windows. Grab one from here, and follow the instructions.
Just before the installation process finishes tick/select the «Add path to environment variable»
option. Then verify that the tools are in your %PATH%:

$ arm-none-eabi-gdb -v
GNU gdb (GNU Tools for Arm Embedded Processors 7-2018-q2-update) 8.1.0.20180315-git
(..)

OpenOCD

There’s no official binary release of OpenOCD for Windows but if you’re not in the mood to compile
it yourself, the xPack project provides a binary distribution, here. Follow the
provided installation instructions. Then update your %PATH% environment variable to
include the path where the binaries were installed. (C:\Users\USERNAME\AppData\Roaming\xPacks\@xpack-dev-tools\openocd\0.10.0-13.1\.content\bin\,
if you’ve been using the easy install)

Verify that OpenOCD is in your %PATH% with:

$ openocd -v
Open On-Chip Debugger 0.10.0
(..)

QEMU

Grab QEMU from the official website.

ST-LINK USB driver

You’ll also need to install this USB driver or OpenOCD won’t work. Follow the installer
instructions and make sure you install the right version (32-bit or 64-bit) of the driver.

That’s all! Go to the next section.

In this mini article, I’ll be going on a few strategies and nuances around
getting a copy of GDB installed for debugging ARM chips.

Like Interrupt? Subscribe to get our latest posts straight to your mailbox.

Table of Contents

  • Introduction
  • Summary of strategies
  • Details on each strategy

    • Binaries from ARM
    • xPack GNU Arm Embedded GCC
    • System package manager
    • Conda
    • Docker
    • SDK-specific tools
    • Build from source
    • crosstool-NG
  • Outro

Introduction

GDB, the GNU Project Debugger, is by default typically compiled to target the
same architecture as the host system. When we talk about “host” and “target
architectures, what we mean is:

  1. the host architecture: where the GDB program itself is run
  2. the target architecture: where the program being debugged is run

Debugging a program that’s running on the same machine as the host might look
like this:

img/installing-gdb/gdb_host_target.drawio.svg

In embedded engineering, we often want to target a foreign architecture (eg, the
embedded device, connected to some debug probe). That setup might look like
this:

img/installing-gdb/gdb_cross_target.drawio.svg

We need a version of GDB that supports the target architecture of the program
being debugged.

In this article, we’re interested in running GDB on an x86-64 or arm64 host and
debugging an arm-v7m (32-bit) target. Getting the right toolchain setup can be
tricky, especially if we want advanced features to be available. I’ll go over
different approaches people use to download and setup GDB and explain the pros
and cons of each of them.

Summary of strategies

I’m going to go through the various ways to install GDB with ARM support, but
first here’s a table summarizing the approaches:

Strategy Binary or source install? Pinned to version Python support 3rd party package manager
Binaries from ARM 📦binary ✅ yes ⚠️ varies per version  
xPack GNU Arm Embedded GCC 📦binary ✅ yes ✅ yes  
System package manager 📦binary ⚠️ varies ⚠️ varies  
Conda 📦binary ✅ yes ✅ yes ⚠️ yes
Docker 📦binary ✅ yes ✅ yes ⚠️ yes
SDK-specific tools 📦binary ⚠️ varies ✅ (usually yes)  
Build from source 📁source ✅ yes ✅ (configurable)  
crosstool-NG 📁source ✅ yes ✅ (configurable)  

Details on each strategy

Binaries from ARM

ARM ships full prebuilt GCC + Binutils toolchains for Linux, Windows, and Mac.
These were originally hosted on launchpad.net, but were moved here around 2016:

https://developer.arm.com/downloads/-/gnu-rm

In 2022, the downloads relocated again to this page:

https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads

These packages are very handy- they include the following components:

  • GCC compiler
  • all binutils
    • GDB
    • LD
    • objdump, etc
  • prebuilt Newlib C library
  • prebuilt “Newlib-Nano” reduced size C library
  • various example linker scripts and startup files

Another benefit- you can have developers on Windows/Linux/Mac all using the same
version of the compiler (doesn’t necessarily guarantee bit-for-bit reproducible
builds, but chances are pretty good).

The same tools can also easily be used in whatever CI system you are using.

Note that these packages are the officially supported toolchain from ARM itself.

There is one gotcha with these packages, though- the Python support is whatever
was configured at build time by ARM. This means if you’re using GDB’s Python
API, you’ll
need to make sure your Python scripts/dependencies/interpreter matches the
interpreter embedded into GDB.

And in the latest release, Python support was dropped in the Mac release:

# check which dynamic libraries the mac arm-none-eabi-gdb binary depends on

# v11.2-2022.02 (no Python support 😔. note the *gdb-py binary is absent from
# the archive)
❯ llvm-otool-14 -L ~/Downloads/gcc-arm-11.2-2022.02-darwin-x86_64-arm-none-eabi/bin/arm-none-eabi-gdb
/home/noah/Downloads/gcc-arm-11.2-2022.02-darwin-x86_64-arm-none-eabi/bin/arm-none-eabi-gdb:
        /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
        /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 902.1.0)

# v10.3-2021.10 (python2.7! in 2021!)
❯ llvm-otool-14 -L ~/Downloads/gcc-arm-none-eabi-10.3-2021.10-mac/bin/arm-none-eabi-gdb-py
/home/noah/Downloads/gcc-arm-none-eabi-10.3-2021.10-mac/bin/arm-none-eabi-gdb-py:
        /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
        /System/Library/Frameworks/Python.framework/Versions/2.7/Python (compatibility version 2.7.0, current version 2.7.10)
        /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1575.17.0)
        /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)

# still present in the linux version of v11.2-2022.02 though. But it's a
# somewhat venerable python3.6, which I don't have installed right now 😅
❯ ldd ~/Downloads/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin/arm-none-eabi-gdb
        linux-vdso.so.1 (0x00007ffd3fd4d000)
        libncursesw.so.5 => /lib/x86_64-linux-gnu/libncursesw.so.5 (0x00007f9f6c717000)
        libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f9f6c6e8000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9f6c6e3000)
        libpython3.6m.so.1.0 => not found
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9f6c6de000)
        libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f9f6c6d7000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9f6c5f0000)
        libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f9f6c5bf000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9f6c393000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9f6c373000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9f6c14b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9f6c764000)

This could potentially be a pretty serious problem if there is some tooling or
scripting that uses the Python API and the release for your host system doesn’t
have Python enabled.

xPack GNU Arm Embedded GCC

The xPack Project provides a prebuilt gcc-arm
toolchain:

  • https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/

They tend to be pretty up-to-date, and more reliably include Python support.

There’s also build documentation, if you’d like to tweak the package:

  • https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/blob/xpack/README-BUILD.md

Overall pretty simple and easy to use, and make a very good alternative to the
official ARM GCC toolchains! I’ve used it as a drop-in replacement for the ARM
GCC toolchains, and it’s working very well.

Advantages:

  • wider host support (darwin-arm64) than the official releases
  • more consistent Python support across host platform versions
  • documented + reproducible build instructions

Disadvantages:

  • only a single Python version supported per release
  • similarly non-customizable as the official ARM GCC packages. you get what you
    get and you don’t get upset!

System package manager

Depending on your host platform (Linux, Mac, Windows, *BSD, etc), you may or
may not have a built-in or defacto package manager. For example, on Linux, you
may have one of:

  • apt-get / apt (Debian, Ubuntu)
  • pacman (Arch)
  • yum (Red Hat)

Mac users will often install homebrew, since there is no
built-in package manager.

Windows users may use something like chocolately or
the recent
winget tool.

It’s certainly convenient to be able to do something as simple as this to
acquire a version of gdb compatible with arm targets:

sudo apt install gdb-multiarch

On Linux, those gdb-multiarch packages usually have a lot of supported
targets. On my Ubuntu 22.04 machine, it’s 214 supported targets!

(the sed one-liner is from below)

# using the one liner from below to list supported targets
❯ gdb-multiarch --batch -nx --ex 'set architecture' 2>&1 | tail -n 1 | sed 's/auto./\n/g' | sed 's/,/\n/g' | sed 's/Requires an argument. Valid arguments are/\n/g' | sed '/^[ ]*$/d' | sort | uniq | wc -l

214

Of course, it’s only important that the targets we’re interested in are
supported.

There are a few downsides to using a package manager to install the tools:

  • you are at the mercy of the available packages (or you need to create and
    maintain a package, which is probably more difficult than a normal from-source
    build!)
  • available versions could be pulled from registries for no reason, leaving your
    environment stranded
  • bugs in package versions might be difficult to deal with, since packages may
    not be updated frequently
  • package managers are usually host-specific (homebrew does support some Linux
    packages though!), which means if your development team is using different
    host machines, it may be difficult to standardize on one set of tools

Conda

Conda is a cross-platform package manager, which we’ve
written about before on Interrupt:

  • Managing Developer Environments with
    Conda

It behaves quite similarly to system package managers, but can be used on
different hosts (Linux/Mac/Windows), so a development team can standardize
tooling without requiring a single host platform!

This is great! But there are a few downsides:

  • same as with system package managers, we are relying on externally maintained
    tooling packages
  • complex conda environments can get into dependency issues when updating
    packages
  • not all packages will provide versions for all of Linux + Mac + Windows
  • creating + maintaining conda packages can be pretty difficult, especially
    since cross-building conda packages is not yet fully supported

Plug (note: the author is an employee at Memfault), Memfault maintains conda
packages for multi-arch GDB:

  • https://anaconda.org/Memfault/multi-arch-gdb
  • https://docs.memfault.com/docs/mcu/coredump-elf-with-gdb/#installing-multi-architecture-gdb-with-conda

Docker

Docker is a well-known technology for freezing
dependencies, by using virtualization.

For development tooling, you can set up a Docker image that contains all the
tooling you need to build + debug an embedded project:

# select a specific SHA, to strictly pin the base image
FROM ubuntu:22.04@sha256:bace9fb0d5923a675c894d5c815da75ffe35e24970166a48a4460a48ae6e0d19

ARG DEBIAN_FRONTEND=noninteractive

# install GDB + GCC for ARM
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc-arm-none-eabi \
    gdb-multiarch

This approach has a few advantages:

  • anyone using the same Docker image should be using exactly the same version
    of the tools
  • the same Docker image can be used in your test / CI infrastructure, which
    simplifies things greatly
  • Docker images can be used on Linux/Mac/Windows without too much host setup

And a few downsides:

  • running Docker images on Mac or Windows is likely going to be lower
    performance than on Linux, especially for file IO, since on those platforms
    Docker containers are running in a virtualization environment
  • accessing host data (files) from within the Docker container can be tricky
  • accessing host hardware (USB or Serial ports) can be easy or impossible,
    depending on host platform
  • maintaining the Docker image itself requires some knowledge of Docker (though
    there are a lot of good tutorials online)

Plug- Memfault also provides a Docker image for running gdb-multiarch:

  • https://docs.memfault.com/docs/mcu/coredump-elf-with-gdb/#multi-architecture-gdb-using-docker

SDK-specific tools

SDK Vendors (and IDE vendors too!) will often package copies of GDB, along with
other toolchain components, to make it easy to get started with their platform.

For example, Zephyr RTOS provides pre-built toolchains, that include the
appropriate GDB versions:

  • https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.14.2

ESP-IDF from Espressif provides similar tool packages:

  • https://github.com/espressif/binutils-gdb/releases/esp-gdb-v11.2_20220715

Advantages:

  • these packages are often well-tested by the vendors, and you may even be able
    to get support if you encounter issues!
  • generally support all Linux/Mac/Windows these days

Disadvantages:

  • often these packages are very tailored to the particular environment (which
    usually is just fine), including custom patches for example
  • Python support can be pretty variable- some packages won’t have Python support
    at all, or it will only be for a specific version.
  • external dependencies may not be provided (eg libpython), and you’ll have to
    bring your own
  • can be based on pretty old GDB/binutils releases, so there might be
    long-resolved bugs present, or missing newer optimizations + features

Build from source

Building a custom copy of GDB is one
way to enable support for the necessary architecture.

You might for example build GDB enabling all targets:

❯ ./configure
  --target="arm-elf-linux"
  --enable-targets=all
  --with-python
❯ make -j $(nproc)

This results in a nicely tuned copy of GDB- you can select only the features
needed, enable different optimizations, select the correct Python version to
integrate, etc., and are in full control of your software supply chain!

The downsides of from-source builds (in general):

  • can be challenging to build for Windows or other non-Unix platforms
  • need to maintain build tooling + binary repositories
  • using custom builds, you might encounter edge cases or warts that have been
    solved in more widely used copies of the same software

Quick note- if you want to see which architectures a given gdb binary
supports, here’s a shell “one-liner” that can be useful (taken from
here):

gdb --batch -nx --ex 'set architecture' 2>&1 | \
  tail -n 1 | \
  sed 's/auto./\n/g' | \
  sed 's/,/\n/g' | \
  sed 's/Requires an argument. Valid arguments are/\n/g' | \
  sed '/^[ ]*$/d' | sort | uniq

Warning, this won’t work with the built-in sed on macos, it’s too old and
doesn’t have the necessary GNU extensions.

crosstool-NG

From the website:

Crosstool-NG is a versatile (cross) toolchain generator. It supports many
architectures and components and has a simple yet powerful menuconfig-style
interface.

It’s quite easy to get started with crosstool-ng, and there’s a good number of
example configurations provided. A quickstart might run like this:

# 1. build crosstool-ng itself

# fetch the crosstool-ng repo
❯ git clone https://github.com/crosstool-ng/crosstool-ng
❯ cd crosstool-ng
❯ git checkout crosstool-ng-1.25.0

# build crosstool-ng
❯ ./bootstrap && ./configure --enable-local && make -j$(nproc)

# 2. now to build a toolchain

# use one of the example configs
❯ ./ct-ng arm-nano-eabi
# you can use './ct-ng menuconfig' to adjust the config, eg, add CT_DEBUG_GDB=y
# to enable building gdb

# build the toolchain. this can take a while- on my middle-range laptop, it
# took about 12 minutes
❯ ./ct-ng build

# now to test it (the toolchain output needs to be inserted to path)export PATH=$PWD/.build/arm-nano-eabi/buildtools/bin:$PATHexport PATH=$PWD/.build/arm-nano-eabi/build/build-gdb-cross/gdb:$PATH
# confirm gdb is the freshly built one
❯ which gdb
/home/noah/dev/github/crosstool-ng/.build/arm-nano-eabi/build/build-gdb-cross/gdb/gdb
# run the check-architecture script from above
❯ gdb --batch -nx --ex 'set architecture' 2>&1 | tail -n 1 | sed 's/auto./\n/g' | sed 's/,/\n/g' | sed 's/Requires an argument. Valid arguments are/\n/g' | sed '/^[ ]*$/d' | sort | uniq

 arm
 arm_any
 armv2
 armv2a
 armv3
 armv3m
 armv4
 armv4t
 armv5
 armv5t
 armv5te
 armv5tej
 armv6
 armv6k
 armv6kz
 armv6-m
 armv6s-m
 armv6t2
 armv7
 armv7e-m
 armv8.1-m.main
 armv8-a
 armv8-m.base
 armv8-m.main
 armv8-r
 ep9312
 iwmmxt
 iwmmxt2
 xscale

# build an uninteresting programecho "int main(){return 0;}" > main.c
❯ arm-nano-eabi-gcc -mcpu=cortex-m0plus -ggdb3 -nostdlib -Wl,--entry=main -o arm.elf main.c
# check the elf it built with binutils
❯ gdb arm.elf -batch --ex 'disassemble /s main'
threads module disabled
Dump of assembler code for function main:
main.c:
1       int main(){return 0;}
   0x00008000 <+0>:     push    {r7, lr}
   0x00008002 <+2>:     add     r7, sp, #0
   0x00008004 <+4>:     movs    r3, #0
   0x00008006 <+6>:     movs    r0, r3
   0x00008008 <+8>:     mov     sp, r7
   0x0000800a <+10>:    pop     {r7, pc}
End of assembler dump.

❯ arm-nano-eabi-objdump --disassemble=main --source arm.elf

arm.elf:     file format elf32-littlearm


Disassembly of section .text:

00008000 <main>:
int main(){return 0;}
    8000:       b580            push    {r7, lr}
    8002:       af00            add     r7, sp, #0
    8004:       2300            movs    r3, #0
    8006:       0018            movs    r0, r3
    8008:       46bd            mov     sp, r7
    800a:       bd80            pop     {r7, pc}

❯ arm-nano-eabi-size -Ax arm.elf
arm.elf  :
section             size      addr
.text                0xc    0x8000
.persistent          0x0   0x1800c
.noinit              0x0   0x1800c
.comment            0x22       0x0
.debug_aranges      0x20       0x0
.debug_info         0x48       0x0
.debug_abbrev       0x3a       0x0
.debug_line         0x3c       0x0
.debug_frame        0x2c       0x0
.debug_str        0x2c12       0x0
.debug_macro       0xa7d       0x0
.ARM.attributes     0x2c       0x0
Total             0x37f3

You end up with a fully-baked toolchain set up to your specifications, without a
ton of work manually configuring and building various packages.

The Zephyr project currently bases its toolchain builds on crosstool-NG, with
some custom sources:

https://github.com/zephyrproject-rtos/sdk-ng/tree/61bd806b61e9fa92a90c8e1d81237353556a0560

And the famous Compiler Explorer project also uses crosstool-NG for cross
toolchain building:

https://github.com/compiler-explorer/gcc-cross-builder/blob/190e5ba158c42529090fa8ea5f33a4f79b6e179b/Dockerfile#L77

Outro

I learned a lot wading through the different varieties of GDB floating around! I
was particularly surprised at how much Python support varied across all these
options. That’s certainly a spot that’s caused me headaches in the past.

Overall I think the choice of toolchain/GDB depends on these criteria:

  • does your SDK/platform already provide a nicely working copy?
  • do you have specific needs that are not met by existing options?

The biggest difficulty overall seems to be sourcing a copy with

  1. the version of Python your tools are relying on
  2. supports Linux/Mac/Windows (depending on what developers on your team are
    using)

Though it might seem like an option of last resort, I was pleasantly surprised
at how straightforward it was to build GDB from source, and crosstool-NG gets
a special shoutout for really simplifying building a complete cross toolchain
🙌!

The great thing about these tools being open source: we have lots of options!

(also could be considered a downfall 😅)

Thanks so much for reading!

Like Interrupt? Subscribe to get our latest posts straight to your mailbox.

See anything you’d like to change? Submit a pull request or open an issue at GitHub


Noah Pendleton is an embedded software engineer at Memfault. Noah previously worked on embedded software teams at Fitbit and Markforged

Install


All systems
curl cmd.cat/arm-none-eabi-gdb.sh

Debian

Debian

apt-get install gdb-arm-none-eabi


Ubuntu
apt-get install gdb-arm-none-eabi

Arch

Arch Linux

pacman -S arm-none-eabi-gdb


Fedora
dnf install arm-none-eabi-gdb


Windows (WSL2)
sudo apt-get update
sudo apt-get install gdb-arm-none-eabi


Raspbian
apt-get install gdb-arm-none-eabi


Dockerfile

dockerfile.run/arm-none-eabi-gdb

gdb-arm-none-eabi

GNU debugger for ARM Cortex-A/R/M processors

Bare metal GNU debugger for embedded ARM chips using Cortex-M0/M0+/M3/M4, Cortex-R4/R5/R7 and Cortex-A* processors. GDB is a source-level debugger, capable of breaking programs at any specific line, displaying variable values, and determining where errors occurred.

arm-none-eabi-gdb

The GNU Debugger for the ARM EABI (bare-metal) target

  • Aria soho usb driver windows 10
  • Arm none eabi gcc for windows
  • Argox os 2130d драйвер windows 10
  • Argox cp 2140 драйвера для windows
  • Arch linux dual boot windows