OPENJTAG debugging learning (3): debugging using the gdb command line

Debugging with gdb command line

1 Introduction to gdb command

  • start and exit
    start and exit

  • file operation

file operation

  • view source

view source

  • breakpoint operation
    breakpoint operation

  • Watchpoint Operations
    Watchpoint Operations

  • data manipulation

data manipulation

  • execute program
    execute program

  • help
    help

  • other commands

other commands

2 Use the arm-elf-gdb command to debug the program (take S3C2440 as an example)

Take the debugging of the leds program on the CD as an example (note: start OpenOCD first, if you want to debug S3C6410, set the "Work Dir" of OpenJTAGGUI to E:\eclipse_projects\6410):

insert image description here
If you don't want to enter so many commands, you can write them to a file, such as gdb.init; then start gdb like this:

arm-elf-gdb -x gdb.init leds_elf

The content of gdb.init is attached:

target remote localhost:3333 
monitor halt 
monitor arm920t cp15 2 0 // 对于S3C6410,这句改为 monitor arm mcr 15 0 1 0 0 0
monitor step 
load 
break main // 对于S3C6410,有些例子没有main函数,有xxxxx函数,这句改为:break xxxxx
continue

3 Developing with Eclipse

Eclipse is the graphical front end of gdb. If you don't want to use GDB in the command line, you can use Eclipse.

Eclipse is the graphical foreground of gdb (including arm-elf-gdb, arm-linux-gdb) . Debugging with Eclipse is essentially debugging with gdb.

When debugging with gdb, gdb will use the link address of the program . For example, at the break point of the main function, gdb will find the corresponding instruction in the memory according to the link address of the main function, and modify this instruction into a special instruction . When the program executes this special instruction, it will stop.

So, when debugging with gdb, the program should be located at its link address. This is why when debugging u-boot below, it is necessary to initialize SDRAM or DDR first , and then download u-boot to 0x33f80000 (S3C2410/S3C2440) or 0x57e00000 (S3C6410) before debugging.

If the link address of the program to be debugged is on the on-chip RAM, there is no need to initialize SDRAM or DDR.

1 Start Eclipse and make simple settings

Under the Eclipse installation directory C:\Program Files\eclipse, double-click to start Eclipse, wait for a while, and you can see the interface shown in Figure 2.38. Set the working directory to E:\eclipse_projects inside, and select "Use this as the default and do not ask again", which means to use E:\eclipse_projects as the default directory, and no more prompts.

insert image description here

In Figure 2.38, click OK to get the interface shown in Figure 2.39.

insert image description here

The icon on the right in Figure 2.39 is named “Workbench”, click it to get the interface shown in Figure 2.40.

insert image description here

2 Create a new Eclipse project

  • (1) Create a project:
    In the interface shown in Figure 2.40, select the menu item “File -> New -> C Project”, as shown in Figure 2.41.

insert image description here
In the subsequent window (as shown in Figure 2.42), specify the project name, select "Makefile project->EmptyProjects", "Other Toolchain", and click the "Finish" button.

insert image description here

  • (2) Add files:

When creating the leds project, if there are already source files in the E:\eclipse_projects\leds directory, these files will be automatically added to the project. If the E:\eclipse_projects\leds directory is empty, you can use the following methods to import files when adding new files.

Next, create a test file test_file_to_add.txt under E:\eclipse_projects, and then use it as an example to introduce how to add files to the project.

Select the menu item “File -> Import…”, and then select “File System” as the file source, as shown in Figure 2.33.

insert image description here
Click "Next" to open the "Import" dialog box, specify the source directory "From directory", select the file to be imported, and specify the destination directory "Into folder". As shown in Figure 2.44, click the "Finish" button to add files.

insert image description here
So far, the new Eclipse project has been created, as shown in Figure 2.45. Double-click the file name on the left to open it for editing.

insert image description here

  • 3 Compile and clear the program

Note: Many programs cannot be compiled under windows, such as u-boot and linux kernel, they can only be compiled under Linux, and then the executable program can be debugged under windows. For these programs, the content of this section does not apply.

After the Eclipse project is established, in the "Project" menu, click to remove the mark in front of "Build Automatically", which means that the project will not be automatically compiled, as shown in Figure 2.46

insert image description here
Now you can use the buttons to compile and clean the program. Click the menu "Project -> Build Project" to start compiling the program, as shown in Figure 2.47; the compilation process is shown in Figure 2.48.

insert image description here
insert image description here
The effect of compiling is exactly the same as executing the "make all" command on the command line.

The way to clear the program is to select the menu "Project -> Clean..." (as shown in Figure 2.49), and a dialog box will pop up (as shown in Figure 2.50).

insert image description here
insert image description here
In Figure 2.50, do not select "Start a build immediately", then click "OK" to clear the program.

4 Use Eclipse to debug the Linux kernel

Note: The OpenJTAG CD does not include the Linux kernel. To debug the kernel, you need to obtain the source code from your development board CD, and compile vmlinux and uImage.

Eclipse is the graphical foreground of gdb (including arm-elf-gdb, arm-linux-gdb). Debugging with Eclipse is essentially debugging with gdb.

When debugging with gdb, gdb will use the link address of the program. For example, at the break point of the main function, gdb will find the corresponding instruction in the memory according to the link address of the main function, and modify this instruction into a special instruction. When the program executes this special instruction, it will stop.

So, when debugging with gdb, the program should be located at its link address . This is also the reason why you need to initialize SDRAM or DDR first when debugging u-boot, and then download u-boot to 0x33f80000 (S3C2410/S3C2440) or 0x57e00000 (S3C6410).

Debugging the Linux kernel under Eclipse is almost the same as debugging u-boot. The difference is that the link address of Linux is generally a virtual address . For example, the link address of the kernel of S3C2410/S3C2440 is 0xC0008000, and this address does not correspond to the actual memory before starting the MMU.

Therefore, you cannot use gdb for debugging before starting the MMU. You need to use openocd's own commands to let it execute until the MMU is started; after starting the MMU, you can use gdb to debug.

When does the MMU finish booting? This requires looking at the source code of Linux. For the kernel of ARM architecture, when the following red , it means that the MMU has been started.

__turn_mmu_on: 
	mov r0, r0 
	mcr p15, 0, r0, c1, c0, 0 @ write control reg 
	mrc p15, 0, r3, c0, c0, 0 @ read id reg 
	mov r3, r3 
	mov r3, r3 
	mov pc, r13

To use eclipse to debug the kernel, it is divided into these 4 steps:

  • ① First use u-boot to read the kernel into memory: read from Flash or download through the network.
  • ② Use "hardware breakpoint" on the telnet interface of openocd to break on the physical memory corresponding to "__turn_mmu_on".
  • ③ Start the kernel. When the kernel stops at "__turn_mmu_on", continue to execute the "step" command several times. After seeing that the MMU is started, delete the hardware breakpoint set in step ②.
  • ④ Use eclipse for source-level debugging

Supplementary knowledge: ARM architecture processors only have two hardware breakpoints (breakpoint/watchpoint), and software breakpoints are simulated by using one hardware breakpoint, which can realize countless software breakpoints.

The two hardware breakpoints of ARM can be set to monitor address signals and monitor data signals. In other words, it can be set to these two situations:

  • a. When the address signal sent by the CPU is equal to a certain value, stop;
  • b. When the digital signal sent by the CPU is equal to a certain value, stop.

The hardware breakpoint is set to the first case. If you use the hardware breakpoint, you can only set up to two breakpoints (two addresses) in the program.

The software breakpoint is set to the second situation. When using it, the instruction to be interrupted in the program is generally taken out and saved, and then replaced with a specific data. When the CPU executes that instruction, it will When this data appears on the data signal, the CPU will stop;

When continuing to execute, the previously saved instructions will be executed first. When debugging a program, you can set countless software breakpoints.

The advantage of hardware breakpoints is that the program will not be modified, as long as the program executes to a certain address, it will stop .

A software breakpoint will "save, modify, and resume execution" the instruction of the breakpoint, which also means that when the breakpoint is interrupted, the program must already be at its load address .

And when we execute step ①, where the kernel is placed is very arbitrary. To avoid trouble, use "hardware breakpoint" in step ②.

The following takes debugging the core of S3C2440 as an example to demonstrate.

  • ① On the u-boot interface, download the kernel to the memory (the following command uses the tftp command to download the kernel, for reference):
OpenJTAG> set ipaddr 192.168.1.17
OpenJTAG> set serverip 192.168.1.5
OpenJTAG> tftp 32000000 uImage
ERROR: resetting DM9000 -> not responding 
dm9000 i/o: 0x20000000, id: 0x90000a46 
DM9000: running in 16 bit mode 
MAC: 08:00:3e:26:0a:5b 
could not establish link 
TFTP from server 192.168.1.5; our IP address is 192.168.1.17 
Filename 'uImage'.
Load address: 0x32000000 
Loading: ################################################################# 
 ################################################################# 
 ################################################################# 
 ################################################################# 
 ################################################################# 
 ##################################### 
done 
Bytes transferred = 1848720 (1c3590 hex)
  • ② In the telnet operation interface of openocd, set a breakpoint:
    look at the System.map file obtained when compiling the kernel, and search for "__turn_mmu_on" to get the following line:
c0008060 t __turn_mmu_on

The MMU has not been started at the beginning. For S3C2410/S3C2440, the physical address corresponding to "c0008060" is "0x30008060". Set a breakpoint with the following command (hardware breakpoint must be set):

halt # 先停止开发板 
bp 0x30008060 4 hw # 设置硬件断点 
resume # 继续运行

There is a self-extracting program at the beginning of uImage, which decompresses the real kernel and puts it in the memory starting at 0x30008000. After decompression, it jumps to 0x30008000 to execute the real kernel.

The self-extracting program starts to execute from 0x30008000, and the decompressed kernel also runs from 0x30008000. So when the kernel starts, the address 0x30008060 is executed twice.

  • ③ Start the kernel in u-boot:

Execute the following command:

bootm 32000000

The development board will immediately stop running at 0x30008060, and the current running is the self-extracting program of the kernel. The following commands in the telnet operation interface of openocd allow the development board to continue to execute:

resume

Then the development board will stop running again at 0x30008060, and the current running is the real, decompressed kernel. Execute the "step" command twice on the telnet operation interface of openocd, and you can see the following words:

MMU: enabled, D-Cache: enabled, I-Cache: enabled

Then you can delete the breakpoint in the telnet interface, just execute "rbp 0x30008060".
All commands executed on the telnet interface of openocd are shown in Figure 2.80, pay attention to the cooperation with u-boot.

insert image description here

  • ④ Continue to debug the kernel in eclipse: the
    settings in eclipse are almost the same as when debugging u-boot, as shown in Figure 2.81~2.84. There are two small differences:
  • a. s3c2440_gdb.init is not used in Figure 2.82. The function of this file is to connect gdb to openocd and initialize the memory. After executing this step, u-boot has already initialized the memory and loaded the kernel into the memory, so do not
    initialize the memory again.
  • b. The commands in Figure 2.83 are as follows, the first command is to connect gdb to openocd:
target remote 127.0.0.1:3333 # 图2.82里没用s3c2440_gdb.init,所以要在命令里指定gdb的目标 
set substitute-path /work/projects/jz2440/linux-2.6.22.6 E:/eclipse_projects/linux-2.6.22.6_jz2440 # 内核的编译路径、当前路径 
break start_kernel # 不要使用load命令再次加载,因为内核已经在内存里了,直接打断点
c # 继续运行

insert image description here
Note: uImage is used in u-boot, and vmlinux is used here.

insert image description here
insert image description here
insert image description here

References:

"Eclipse, OpenOCD, OpenJTAG Tutorial"

Guess you like

Origin blog.csdn.net/weixin_45264425/article/details/132004195