? ǰ��

Ƕ��ʽ����������Ƕ��ʽ�����������ս�ԵĻ���֮һ����PC������ͬ��Ƕ��ʽϵͳ��Դ���ޡ������ֶ����ޣ���Ҫ����ר�ŵĵ������ۺͼ��ɡ����Ľ������ۻ�����ʵ��Ӧ�ã�ȫ�����Ƕ��ʽ�������Լ�����

? �������ۻ���

ʲô���������ԣ�

����������Software Debug����������������Ƿ�������ʧЧ����λ�������󲢽����޸��Ĺ��̡�

1
�������Թ��� = �������� �� ��λ���� �� �޸����� �� ��֤�޸�

���Ե���Ҫ��

? ͳ��������ʾ��

  • ��������ʱ��һ��ռ�����������ڵ� 50%����
  • �����������к�ʱ����һ��
  • �ܶ���Ŀ�������������ڲ��ܶ�λ��bug��
  • ����ϵͳ���Ӷ����ӣ����Լ�����Ҫͬ������

Ƕ��ʽ���Ե�������

��PC����������ȣ�Ƕ��ʽ���Ծ��������ص㣺

�ص� PC���� Ƕ��ʽ����
��Դ���� �ڴ桢�洢���� ��Դ��������
���Ի��� �ḻ�ĵ��Թ��� �����ֶ�����
ʵʱ�� ʵʱ��Ҫ�󲻸� �ϸ��ʵʱ��Ҫ��
Ӳ������ ��׼��Ӳ��ƽ̨ �߶������ض�Ӳ��
����Ӱ�� ������������ ������Ӳ��

? ���Թ��ߺͷ���

Ӳ�����Թ���

1. JTAG������

JTAG��Joint Test Action Group������õ�Ӳ�����Խӿڣ�

1
2
3
4
5
6
7
�ص㣺
? ���Ե�����������
? ֧�ֵ�������
? ���Բ鿴�Ĵ���״̬
? ֧�ֶϵ�����
? ��Ҫר�ŵĵ�����Ӳ��
? ռ��MCU�ĵ�����Դ

����JTAG��������

  • J-Link: Segger��˾��Ʒ������ǿ��֧�ֶ���MCU
  • ST-Link: ST��˾��Ʒ��ר������STM32����
  • OpenOCD: ��Դ���Է������ɱ�����

2. SWD���Խӿ�

SWD��Serial Wire Debug����ARM�Ƴ��ĵ��Խӿڣ�

1
2
3
4
5
���ƣ�
? ֻ��Ҫ2���ߣ�SWDIO��SWCLK��
? ��JTAG��ʡ����
? ���Թ�������
? ֧���Ȳ��

3. �߼�������

���ڷ��������ź�ʱ��

1
2
3
4
# �����߼�������
- Saleae Logic Pro # �߶˲�Ʒ����������ǿ��
- DSLogic Plus # ��ԴӲ�����Լ۱ȸ�
- PulseView # ��Դ������֧�ֶ���Ӳ��

4. ʾ����

���ڷ���ģ���źź�ʱ��

1
2
3
4
5
Ӧ�ó�����
? ��Դ�Ʋ�����
? �ź������Լ��
? ʱ���ϵ��֤
? EMC���ⶨλ

�������Թ���

1. GDB������

GDB����ǿ��������е�������

1
2
3
4
5
6
7
8
9
10
11
12
# ����GDB����
gdb program # ��������
(gdb) run # �����
(gdb) break main # ��main�������öϵ�
(gdb) break file.c:100 # ��ָ�������öϵ�
(gdb) continue # ����ִ��
(gdb) step # ����ִ�У����뺯����
(gdb) next # ����ִ�У������뺯����
(gdb) print variable # ��ӡ����ֵ
(gdb) info registers # �鿴�Ĵ���
(gdb) backtrace # �鿴����ջ
(gdb) quit # �˳�����

2. ���ɿ�������

Keil MDK��

1
2
3
4
5
6
7
���ƣ�
? �����Ѻã�����ʹ��
? ���ɶȸߣ�����������
? ֧�ֶ���ARM�ں�
? ���湦��ǿ��
? ��ҵ�������۸񰺹�
? ��Ҫ֧��ARM�ܹ�

IAR Embedded Workbench��

1
2
3
4
5
6
7
���ƣ�
? �����Ż�����ǿ
? ֧�ֶ��ּܹ�
? ���Թ�������
? ��̬��������
? �۸񰺹�
? ѧϰ���߶���

STM32CubeIDE����ѣ���

1
2
3
4
5
6
7
���ƣ�
? ��ȫ���
? ����Eclipse�����ܷḻ
? ����STM32���ù���
? ֧�ֶ��ֵ�����
? ��Ҫ���STM32
? �����ٶȽ���

3. ��̬��������

PC-lint/PC-lint Plus��

1
2
3
4
5
6
# ��鳣������
- δ��ʼ������
- �ڴ�й©
- ����Խ��
- ����ת������
- ��������

Cppcheck����Դ����

1
2
3
# ��װ��ʹ��
sudo apt install cppcheck
cppcheck --enable=all src/

? �������Գ���

1. ϵͳ�޷�����

����ԭ����

  • ʱ�����ô���
  • �ڴ��ʼ������
  • �����������
  • Ӳ����������

���Բ�����

1
2
3
4
5
1. ����Դ��ʱ��
2. ʹ��JTAG���ӣ��鿴PCָ��λ��
3. ����ִ����������
4. ����ڴ�ӳ������
5. ��֤Ӳ������

2. ���������쳣

Hard Fault�쳣������

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Hard Fault��������
void HardFault_Handler(void) {
// �����ֳ���Ϣ
__asm volatile (
"TST lr, #4 \n"
"ITE EQ \n"
"MRSEQ r0, MSP \n"
"MRSNE r0, PSP \n"
"B hard_fault_handler_c \n"
);
}

void hard_fault_handler_c(uint32_t *hardfault_args) {
volatile uint32_t stacked_r0;
volatile uint32_t stacked_r1;
volatile uint32_t stacked_r2;
volatile uint32_t stacked_r3;
volatile uint32_t stacked_r12;
volatile uint32_t stacked_lr;
volatile uint32_t stacked_pc;
volatile uint32_t stacked_psr;

stacked_r0 = ((uint32_t)hardfault_args[0]);
stacked_r1 = ((uint32_t)hardfault_args[1]);
stacked_r2 = ((uint32_t)hardfault_args[2]);
stacked_r3 = ((uint32_t)hardfault_args[3]);
stacked_r12 = ((uint32_t)hardfault_args[4]);
stacked_lr = ((uint32_t)hardfault_args[5]);
stacked_pc = ((uint32_t)hardfault_args[6]); // �쳣������ַ
stacked_psr = ((uint32_t)hardfault_args[7]);

// ���������öϵ㣬�鿴�쳣��Ϣ
while(1);
}

3. �ڴ��������

ջ��������

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ջ������
#define STACK_CANARY 0xDEADBEEF

void stack_overflow_check(void) {
extern uint32_t _estack;
uint32_t *stack_end = &_estack - 100; // Ԥ��100�ֽ�

if (*stack_end != STACK_CANARY) {
// ջ�����
error_handler();
}
}

// ��ϵͳ��ʼ��ʱ���ý�˿ȸֵ
void init_stack_canary(void) {
extern uint32_t _estack;
uint32_t *stack_end = &_estack - 100;
*stack_end = STACK_CANARY;
}

�ڴ�й©�����

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// �򵥵��ڴ�������
typedef struct {
void *ptr;
size_t size;
const char *file;
int line;
} mem_block_t;

#define MAX_MEM_BLOCKS 100
static mem_block_t mem_blocks[MAX_MEM_BLOCKS];
static int mem_block_count = 0;

void* debug_malloc(size_t size, const char *file, int line) {
void *ptr = malloc(size);
if (ptr && mem_block_count < MAX_MEM_BLOCKS) {
mem_blocks[mem_block_count].ptr = ptr;
mem_blocks[mem_block_count].size = size;
mem_blocks[mem_block_count].file = file;
mem_blocks[mem_block_count].line = line;
mem_block_count++;
}
return ptr;
}

#define malloc(size) debug_malloc(size, __FILE__, __LINE__)

4. ʵʱ���������

����ִ��ʱ�������

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// ʹ��DWT����������ִ��ʱ��
void dwt_init(void) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0;
}

uint32_t get_cycle_count(void) {
return DWT->CYCCNT;
}

// ʹ��ʾ��
void measure_function_time(void) {
uint32_t start_time = get_cycle_count();

// ִ��Ҫ�����ĺ���
target_function();

uint32_t end_time = get_cycle_count();
uint32_t cycles = end_time - start_time;

// ת��Ϊ΢�루����ϵͳʱ��Ϊ168MHz��
uint32_t us = cycles / 168;

printf("Function execution time: %lu us\n", us);
}

? �߼����Լ���

1. Printf������

�ض���printf����������

1
2
3
4
5
6
7
8
9
10
11
12
13
// �ض���printf��ITM����Ҫ֧��SWO�ĵ�������
int _write(int file, char *ptr, int len) {
for (int i = 0; i < len; i++) {
ITM_SendChar((*ptr++));
}
return len;
}

// �����ض���UART
int _write(int file, char *ptr, int len) {
HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY);
return len;
}

�������������Ϣ��

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifdef DEBUG
#define DBG_PRINT(fmt, args...) printf("DEBUG: " fmt, ## args)
#else
#define DBG_PRINT(fmt, args...)
#endif

// �ּ�������Ϣ
typedef enum {
LOG_ERROR = 0,
LOG_WARN = 1,
LOG_INFO = 2,
LOG_DEBUG = 3
} log_level_t;

#define LOG_LEVEL LOG_INFO

#define LOG(level, fmt, args...) \
do { \
if (level <= LOG_LEVEL) { \
printf("[%s] " fmt "\n", log_level_str[level], ## args); \
} \
} while(0)

2. ���Ի���

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// �Զ�����Ժ�
#ifdef DEBUG
#define ASSERT(expr) \
do { \
if (!(expr)) { \
printf("ASSERT failed: %s, file %s, line %d\n", \
#expr, __FILE__, __LINE__); \
while(1); \
} \
} while(0)
#else
#define ASSERT(expr)
#endif

// ʹ��ʾ��
void buffer_write(uint8_t *buf, int index, uint8_t data) {
ASSERT(buf != NULL);
ASSERT(index >= 0 && index < BUFFER_SIZE);

buf[index] = data;
}

3. ��������

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ���Ź����Լ���
void watchdog_debug_init(void) {
#ifdef DEBUG
// ����ģʽ�½��ÿ��Ź�
__HAL_DBGMCU_FREEZE_IWDG();
#endif
}

// �ֶ�ι������λ��ѭ��λ��
void task_with_watchdog_debug(void) {
HAL_IWDG_Refresh(&hiwdg); // ���1

// �����1
process_step1();

HAL_IWDG_Refresh(&hiwdg); // ���2

// �����2
process_step2();

HAL_IWDG_Refresh(&hiwdg); // ���3
}

4. ���ܷ���

�������ø�����

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ��������/�˳�����
#ifdef FUNCTION_TRACE
#define FUNC_ENTER() printf("ENTER: %s\n", __FUNCTION__)
#define FUNC_EXIT() printf("EXIT: %s\n", __FUNCTION__)
#else
#define FUNC_ENTER()
#define FUNC_EXIT()
#endif

void example_function(void) {
FUNC_ENTER();

// ����ʵ��

FUNC_EXIT();
}

�ڴ�ʹ�ü����

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ��ջʹ��������
void check_stack_usage(void) {
extern uint32_t _estack;
extern uint32_t _sstack;

uint32_t stack_size = (uint32_t)&_estack - (uint32_t)&_sstack;
uint32_t current_sp;

__asm volatile ("mov %0, sp" : "=r" (current_sp));

uint32_t used_stack = (uint32_t)&_estack - current_sp;
uint32_t usage_percent = (used_stack * 100) / stack_size;

printf("Stack usage: %lu/%lu bytes (%lu%%)\n",
used_stack, stack_size, usage_percent);
}

?? ���Ի����

1. OpenOCD����

��װOpenOCD��

1
2
3
4
5
6
7
8
9
10
# Ubuntu/Debian
sudo apt install openocd

# ���Դ�����
git clone https://git.code.sf.net/p/openocd/code openocd
cd openocd
./bootstrap
./configure --enable-stlink --enable-jlink
make
sudo make install

�����ļ�ʾ����

1
2
3
4
5
6
7
8
9
# openocd.cfg for STM32F4
source [find interface/stlink.cfg]
source [find target/stm32f4x.cfg]

# ���ù�������
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 0x8000

# �����
reset_config srst_only

�������ԻỰ��

1
2
3
4
5
6
7
8
9
# ����OpenOCD
openocd -f openocd.cfg

# ����һ���ն�����GDB
arm-none-eabi-gdb firmware.elf
(gdb) target remote localhost:3333
(gdb) monitor reset halt
(gdb) load
(gdb) continue

2. VSCode��������

launch.json������

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug STM32",
"type": "cortex-debug",
"request": "launch",
"servertype": "openocd",
"cwd": "${workspaceRoot}",
"executable": "./build/firmware.elf",
"configFiles": [
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"svdFile": "./STM32F407.svd",
"runToMain": true,
"showDevDebugOutput": true
}
]
}

? �������ʵ��

1. ���Բ���

�ֲ���Է���

1
Ӧ�ò� �� �м���� �� ������ �� Ӳ����

���ַ���λ��

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// �ڿ��ɴ�����м����Ӽ���
void suspicious_function(void) {
// �����1
process_part1();

// ����1
printf("Checkpoint 1: OK\n");

// �����2
process_part2();

// ����2
printf("Checkpoint 2: OK\n");

// �����3
process_part3();
}

2. ����������֤

�����Ա����

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// �������
int safe_divide(int a, int b) {
if (b == 0) {
LOG(LOG_ERROR, "Division by zero!");
return -1;
}
return a / b;
}

// �߽���
void safe_array_access(int *array, int size, int index) {
if (array == NULL) {
LOG(LOG_ERROR, "Null pointer!");
return;
}

if (index < 0 || index >= size) {
LOG(LOG_ERROR, "Array index out of bounds: %d", index);
return;
}

// ��ȫ����
array[index] = 0;
}

3. ������Ϣ����

�ṹ����־��

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typedef struct {
uint32_t timestamp;
log_level_t level;
const char *module;
const char *message;
} log_entry_t;

void structured_log(log_level_t level, const char *module,
const char *fmt, ...) {
char buffer[256];
va_list args;

va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);

printf("[%lu][%s][%s] %s\n",
HAL_GetTick(), log_level_str[level], module, buffer);
}

// ʹ��ʾ��
structured_log(LOG_INFO, "UART", "Received %d bytes", count);

? ���԰�ȫע������

1. ����������ȫ

1
2
3
4
5
6
7
8
// �����汾���Ƴ����Դ���
#ifndef PRODUCTION
#define DEBUG_PRINT(fmt, args...) printf(fmt, ## args)
#define DEBUG_BREAK() __asm("bkpt 0")
#else
#define DEBUG_PRINT(fmt, args...)
#define DEBUG_BREAK()
#endif

2. ������Ϣ����

1
2
3
4
5
6
// ��������־�����������Ϣ
void log_user_info(const char *username, const char *password) {
LOG(LOG_INFO, "User login: %s", username);
// ��Ҫ��¼���룡
// LOG(LOG_INFO, "Password: %s", password); // Σ�գ�
}

? ѧϰ��Դ�͹���

�Ƽ��鼮

  • ��Ƕ��ʽ�������ԡ�- ������
  • ��ARM Cortex-M3Ȩ��ָ�ϡ�- Joseph Yiu
  • ��Ƕ��ʽʵʱ����ϵͳ��C/OS-III��- Jean J. Labrosse

������Դ

ʵ�ù���

  • Ӳ������: J-Link, ST-Link, Logic Analyzer
  • ��������: GDB, OpenOCD, Keil MDK, IAR
  • ��������: Wireshark, PulseView, PC-lint

? �ܽ�

Ƕ��ʽ����������һ���ۺ��Լ�������Ҫ���գ�

  1. ���ۻ���: �˽����ԭ���ͷ�����
  2. ����ʹ��: ����ʹ�ø��ֵ��Թ���
  3. ʵս����: ͨ������ʵ�����۾���
  4. ϵͳ˼ά: ��Ӳ����������ȫջ��������

�����ĵ���

  • ? ϸ�Ĺ۲�: ע��ÿһ���쳣����
  • ? �߼�˼��: �����߼�������λ����
  • ? ��¼�ܽ�: �������˵���֪ʶ��
  • ? �Ŷ�Э��: ����Ѱ������ͷ�������

������Щ���Լ��ܣ������������Ƕ��ʽ����Ч�ʺ�������������


? ���Խ��: “���Ծ�����̽��������Ҫ���ġ�ϸ�ĺ��߼�˼ά��ÿһ��bug����һ�����⣬�ȴ���ȥ�⿪��”

��������Ƽ�: