目录
1、JTAG基本概念
2、OpenOCD基本概念
- OpenOCD连接问题,记得更新驱动。
ESP32-S3 自带usb/jtag初步尝试体验_esp32 usb_watershade2010的博客-CSDN博客
- 开启openOCD监听
- openocd -f board/esp32s3-builtin.cfg
3、GDB基本概念
- ESP32s3中执行文件的目录
- openocd -f board/esp32s3-builtin.cfg
- xtensa-esp32s3-elf-gdb
- 通过idf.py menuconfig设置Blink的GPIO口
- 运行GDB :xtensa-esp32s3-elf-gdb build/blink.elf -x gdbinit
- GDB添加elf文件路径因为elf文件中有debug信息;再给GDB配置启动参数,添加控制文件,用X参数来执行自己编写的初始化参数。
- gdbinit文件内容
set remotetimeout 100 //设置超时时间 target extended-remote :3333 //设置连接端口 set remote hardware-watchpoint-limit 2 //设置硬件支持断点 mon reset halt //重置CPU flushregs //更新寄存器 thb app_main //设置临时中断点在app_main这个中断点中 c //继续执行让中断在app_main这个函数中
- 运行GDB完整命令:xtensa-esp32s3-elf-gdb build/blink.elf -x gdbinit
4、GDB断点设置查看命令
- break N;在代码的第N行设置断点
- inf break:查看当前断点信息
- inf break 1 :查看第一个断点信息
- c 运行程序看看会不会运行到指定的断点处 即继续运行
- 查看断点被执行了几次
- disable 2 :生效断点2
- Ctrl+c 强行中断调试
- enable 2:使能断点
- delete 2:删除断点,不加数字删除所有断点
- l :查看当前的代码
- break D:\Espressif\frameworks\mycode\blink\main\blink_example_main.c:89 (中断在这个文件的第89行)
- break blink_led 设置断点在blink_led();这个函数
- tbreak 85 : 在85行临时设置一个断点只触发一次
5、GDB Watch命令
5.1 与断点设置不同点1
他是通过变量名来设置断点,不是通过行号或是函数名来设置
uint8_t i = 0; uint8_t j = 0; uint8_t k[5]; char *a; void app_main(void) { /* Configure the peripheral according to the LED type */ configure_led(); while (1) { ESP_LOGI(TAG, "Turning the LED %s!", s_led_state == true ? "ON" : "OFF"); blink_led(); /* Toggle the LED state */ s_led_state = !s_led_state; vTaskDelay(CONFIG_BLINK_PERIOD / portTICK_PERIOD_MS); //------------------------ i++; ESP_LOGI(TAG, "i = %d!", i); //------------------------ j++; ESP_LOGI(TAG, "j = %d!", j); //------------------------ i += 2; ESP_LOGI(TAG, "i = %d!", i); //------------------------ for (uint8_t m = 0; m < 5; m++) { k[m] = m; ESP_LOGI(TAG, "k[%d] = %d", m, k[m]); } //------------------------ a = "hello"; ESP_LOGI(TAG, "a = %s", a); //------------------------ a = "hello little"; ESP_LOGI(TAG, "a = %s", a); } }
- watch i :设置变量名i的断点,即通过变量名添加断点
- print i :打印出变量的值,这里是1,因为现在断点在+2位置,+2并没有被执行。
5.2 与断点设置不同点2
程序停止下来的条件,是变量发生变化时;如果变量变化一次后不再变化,那么程序不会再停止到相应的断点;
比如说数组K,对其初始化一次后他的值是固定的不再变化了;
5.3 与断点设置不同点3
观察断点还可以使用表达式
- watch i+j ;只要其中一个变量发生变化,这其中的一个变量或者两个变量的断点就会被触发;就是同时给i、j变量添加断点;
watch a :打印出来的是完整内容 hello \ hello little
wacth *a :打印出来的是首字母 h \ h
6、GDB Print命令
uint8_t i = 0; uint8_t j = 0; uint8_t k[5]; char *a; typedef struct { char *name; uint8_t age; } pople_t; pople_t customer; int n = 0; void square_func(uint8_t i) { n = i * i; } void app_main(void) { /* Configure the peripheral according to the LED type */ configure_led(); while (1) { ESP_LOGI(TAG, "Turning the LED %s!", s_led_state == true ? "ON" : "OFF"); blink_led(); /* Toggle the LED state */ s_led_state = !s_led_state; vTaskDelay(CONFIG_BLINK_PERIOD / portTICK_PERIOD_MS); //------------------------ i++; ESP_LOGI(TAG, "i = %d!", i); //------------------------ j++; ESP_LOGI(TAG, "j = %d!", j); //------------------------ i += 2; ESP_LOGI(TAG, "i = %d!", i); //------------------------ for (uint8_t m = 0; m < 5; m++) { k[m] = m; ESP_LOGI(TAG, "k[%d] = %d", m, k[m]); } //------------------------ a = "hello"; ESP_LOGI(TAG, "a = %s", a); //------------------------ a = "hello little"; ESP_LOGI(TAG, "a = %s", a); //------------------------ customer.age = 10; customer.name = "one"; ESP_LOGI(TAG, "name = %s,age = %d ",customer.name, customer.age); //------------------------ square_func(i); ESP_LOGI(TAG, "squear n %d",n); } }
- 打印出整形
- 打印出不同形式的整形
- 打印出数组
- 打印出字符串
- 打印出结构体
- 打印不同函数中的变量
- 打印不同文件中的变量值
- 改变变量的值
7、GDB Display命令
用于显示变量的值
- dispaly n :打印n的值,在程序停止在断点停止时会自动再次打印出来
- 当程序停止在断点是会显示多个变量的值以及不同的格式
- info display
- disable display 1 1号变量不再显示
- enable display 1 1号变量再使能
- undispaly 1 删除1号变量 或者 delete display 1
8、GDB Examine(X)命令
打印出对应地址的内容
- x /12cb 0x3c025aa0 :12表示打印出12个字符,c表示他是字符型,b表示一个单元即一个字符有一个字节,0x3c025aa内存地址
- set style address foreground green 设置前景色为绿色
- set style address background red 设置背景色为红色
- x /1sb 0x3c025aa0 字符串型
- x /5db 0x3fc9422c 字符数组型 d表示十进制数
- x /1db 0x3fc94232 打印十进制数
9、 GDB Stepping 命令
单步调试命令
- next 运行一行程序
- next 2 运行2行代码
- step 如果next运行到的是函数再step则会进入函数中
- finish 结束当前子函数的运行
- step 3 进入3次子函数需要finish3次才能回来
- until 139 运行到139行
10、GDB TUI(文本用户界面)命令
- tui enable
tui enable 也可以直接配置到启动配置文件中
- tui disable
- update 跳转到断点处
- list 116 跳到116行
- layout asm 显示汇编代码
- layout regs 显示寄存器
- layout src 回到源代码
11、 GDB Jump命令
- 忽略代码 :jump 142 断点打在144jump到142行,从一开始的断点104行到142行中的函数就会被跳不执行然后停止到144行,可以看到142之前的变量i的值为0没有被赋值;且142行到断点144行的会被执行。
- 重新/重复执行代码:jump 108 ;断点在144行然后从从108行开始执行再到144行断点中断,这时候,i这些变量就会被执行;
- 强迫某些不会执行的分支代码执行:断点打在104行,97行和99行是不可能被执行,因为i只会是3的倍数;jump97跳到97行开始执行然后停止到断点104行,这时候就是强制执行97行。
12、 GDB Set命令
- 设置代码变量值 通过改变值来强制运行某段代码
- 设置环境变量的值:临时设置一个仅存在与GDB中的变量值 set $a=0 这里的a不是代码中的a;可以用于一个大数组中查找是否有某个值
13、 GDB Define命令
用于创建用户自己定义的命令
- $argc 环境变量输入参数的个数 $arg0 输入参数的第一个变量
(gdb) define find_data_in_k_array Type commands for definition of "find_data_in_k_array". End with a line saying just "end". >if($argc == 1) >set $a = 0 >while ($a<5) >if(k[$a] == $arg0) >print "id = %d,find %d.\n",$a,$arg0 >end >set $a =$a+1 >end >else >print "The input parameter number is worng!" >end >end
- show user 查看用户定义