Laboratório Prático Completo de Depuração com STM32 + GDB (Do Zero ao HardFault)
Agora vamos consolidar tudo em um laboratório prático realista. A ideia aqui é simular um projeto STM32 baremetal com um erro proposital, e usar o GDB como ferramenta de engenharia — não como ferramenta de curiosidade.
O cenário será o seguinte:
- STM32 (qualquer Cortex-M3/M4/M7 serve)
- Código baremetal simples
- Um ponteiro inválido causando HardFault
- Uso sistemático do GDB para descobrir a causa
Esse tipo de exercício é extremamente formador.
6.1 Código com erro proposital
Considere o seguinte trecho em C:
#include <stdint.h>
volatile uint32_t *ptr;
void faulty_function(void)
{
*ptr = 0x12345678; // ERRO: ptr nunca foi inicializado
}
int main(void)
{
faulty_function();
while(1);
}
Esse código compila perfeitamente. Mas ao executar, vai gerar HardFault porque ptr aponta para endereço indefinido.
Compile com:
-g -Og
Gere o ELF.
Suba o OpenOCD e conecte com:
target extended-remote :3333
monitor reset halt
load
break main
continue
6.2 Executando passo a passo
Quando parar em main:
next
Agora estamos prestes a entrar em faulty_function.
Use:
step
Estamos dentro da função.
Antes de executar a linha problemática:
p ptr
Você verá algo como:
$1 = (volatile uint32_t *) 0x00000000
Ou algum lixo.
Agora execute:
next
O sistema vai cair em HardFault_Handler.
6.3 Investigando o HardFault profissionalmente
Primeiro:
bt
Pode não mostrar corretamente a origem.
Agora vamos aplicar técnica de engenharia.
Veja registradores:
info registers
Observe $sp.
Agora:
x/8xw $sp
Extraia o PC salvo:
p/x *((uint32_t*)$sp + 6)
Suponha que retorne:
0x0800012C
Agora:
list *0x0800012C
Você verá a linha:
*ptr = 0x12345678;
Diagnóstico concluído: acesso inválido por ponteiro não inicializado.
Isso é engenharia de depuração.
6.4 Corrigindo e validando
Corrija código:
volatile uint32_t safe_variable;
volatile uint32_t *ptr = &safe_variable;
Recompile.
Repita processo:
monitor reset halt
load
continue
Agora não ocorre HardFault.
6.5 Segundo laboratório: Stack Overflow real
Agora vamos criar um erro diferente:
void recursive_function(void)
{
uint8_t buffer[1024];
recursive_function();
}
Isso gera overflow rapidamente.
Repita o processo.
Quando cair em HardFault:
info registers
Observe $sp.
Se estiver abaixo do limite de RAM → overflow confirmado.
6.6 Terceiro laboratório: Corrupção silenciosa
Código:
uint32_t array[4];
void corrupt(void)
{
for(int i = 0; i < 10; i++)
array[i] = i;
}
Erro clássico: escreve além do limite.
Coloque watchpoint:
watch array[4]
continue
Quando escrever fora do limite, o GDB interrompe.
Você verá exatamente onde ocorre a corrupção.
Isso é extremamente poderoso para sistemas com DMA ou múltiplas tasks.
6.7 Analisando registradores de fault (SCB)
Quando ocorre HardFault, registre:
x/4xw 0xE000ED28
Esse endereço contém CFSR.
Decodificação:
- Bit 0–7: Memory Management Fault
- Bit 8–15: Bus Fault
- Bit 16–31: Usage Fault
Se for UsageFault por divisão por zero, você verá bit correspondente ativo.
Isso permite classificar tipo exato da falha.
6.8 Laboratório com periférico: GPIO que não responde
Simule erro: esqueça de habilitar clock do GPIO.
Quando LED não acender:
No GDB:
x/1xw RCC_AHB1ENR_ADDRESS
Verifique se bit do GPIO está habilitado.
Se não:
set {uint32_t}RCC_AHB1ENR_ADDRESS |= (1<<0)
Se LED acender → erro confirmado no firmware.
Isso economiza ciclos enormes de debug.
6.9 Método Profissional de Debug (Modelo Mental)
Sempre siga esta ordem:
- Sistema travou?
- Onde está o PC?
- Stack está íntegra?
- Registradores de fault indicam o quê?
- Periférico realmente está habilitado?
- Clock realmente está ativo?
- DMA realmente está escrevendo?
- Interrupção realmente está limpando flag?
Nunca comece alterando código aleatoriamente.
Comece medindo estado.
6.10 Consolidação: Checklist de Depuração STM32
Quando algo falhar:
monitor reset haltbtinfo registersx/8xw $splist *PC- Verificar SCB fault status
- Verificar clock RCC
- Verificar registrador do periférico
- Verificar stack pointer
- Verificar limites de array
Se você seguir esse protocolo, praticamente todo problema embarcado vira resolvível.