使用 QEMU 模拟 cortex-a8 的断点在 gdb 中不起作用
Breakpoint not working in gdb with QEMU simulating cortex-a8
我正在ARM7TDMI中测试一些简单的代码运行ning,由于我在QEMU上没有找到ARM7TDMI模拟器,所以我改用Cortex-a8(我不确定这是否会导致错误,总新手)。
我就是这样 运行 QEMU:
qemu-system-arm -machine realview-pb-a8 -cpu cortex-a8 -nographic -monitor null -serial null -semihosting -kernel main.elf -gdb tcp::51234 -S
我要测试的代码很简单,函数LoadContext()
和SaveContext()
是为IARIDE用arm汇编编写的,而IARIDE是以ARM7TDMI为核心。我把这个汇编文件用IAR编译成目标文件,link下面的代码用arm-none-eabi-gcc
,会不会出现不可预知的错误? (只想使用 gcc 和 QEMU 而不是 IAR...)
int main(void)
{
Running = &taskA;
Running->PC = task1;
Running->SP = &(Running->StackSeg[STACK_SIZE-1]);
LoadContext();
}
void task1(void)
{
register int reg_var = 1;
volatile int vol_var = 1;
SaveContext();
reg_var++;
vol_var++;
SaveContext();
reg_var++;
vol_var++;
LoadContext();
}
所以,当我在 gdb 中设置断点时,它不起作用,我认为它只会进入无限循环。我查看了初始化过程,是:
(gdb)
0x000082f6 in __libc_init_array ()
(gdb)
0x000080e2 in _start ()
(gdb)
0x000080e4 in _start ()
(gdb)
0x000080e6 in _start ()
(gdb)
main () at src/context-demo.c:12
12 int main(void) {
(gdb)
0x000081ea 12 int main(void) {
(gdb)
0x00000008 in ?? ()
(gdb)
0x0000000c in ?? ()
(gdb)
0x00000010 in ?? ()
(gdb)
0x00000014 in ?? ()
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000004 in ?? ()
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000004 in ?? ()
(gdb)
有人知道这里发生了什么吗?感谢任何帮助,谢谢!
如果你告诉 gdb 告诉你它正在执行的汇编指令,你会发现这更容易调试("display /3i $pc" 每次 gdb 停止时都会打印接下来的 3 条指令),并执行单步操作个别指令("stepi")。
某事导致您意外地以低地址 0x8 结束,您需要查明那是什么。要么你真的跳到 0x8,要么你采取了例外。查看每机器指令级别的执行会告诉您它是什么。
这里有一些似是而非的可能性:
- 可执行文件假设它有 RAM 而 realview-pb-a8 没有 RAM——这通常表现为 "writing to the stack (or global variables) silently does nothing and reading from the stack/globals returns 0",所以如果你在全局中有一个函数指针或者你试图推送一个 return 地址到堆栈然后弹出它你会在 0
- 可执行文件被构建为假设它是 运行 在提供 SVC API 的 OS 下——在这种情况下,代码将执行 SVC 指令并且您的代码将崩溃,因为有在 SVC 异常向量
没有什么可以处理的
- 为错误的 CPU 类型构建的可执行文件并执行 UNDEF 的指令(这应该导致执行地址 0x4,即 undef 向量,但我感觉它的 gdbstub 中有一个 qemu 错误可能意味着执行 UNDEF insn 的步骤将不会停止,直到在 UNDEF 向量处执行第一个 insn 之后)
- 构建的可执行文件假定 FPU 始终处于启用状态。当 QEMU 像这样执行 "bare metal" 二进制文件时,CPU 在硬件启动的状态下启动,其中 FPU 被禁用。因此,除非可执行文件的启动代码已明确打开 FPU,否则任何使用 FPU 的指令都将 UNDEF。
我已经按照您的案例的大致概率顺序列出了这些,但无论如何,机器指令的单步执行应该可以确定发生了什么。
我正在ARM7TDMI中测试一些简单的代码运行ning,由于我在QEMU上没有找到ARM7TDMI模拟器,所以我改用Cortex-a8(我不确定这是否会导致错误,总新手)。
我就是这样 运行 QEMU:
qemu-system-arm -machine realview-pb-a8 -cpu cortex-a8 -nographic -monitor null -serial null -semihosting -kernel main.elf -gdb tcp::51234 -S
我要测试的代码很简单,函数LoadContext()
和SaveContext()
是为IARIDE用arm汇编编写的,而IARIDE是以ARM7TDMI为核心。我把这个汇编文件用IAR编译成目标文件,link下面的代码用arm-none-eabi-gcc
,会不会出现不可预知的错误? (只想使用 gcc 和 QEMU 而不是 IAR...)
int main(void)
{
Running = &taskA;
Running->PC = task1;
Running->SP = &(Running->StackSeg[STACK_SIZE-1]);
LoadContext();
}
void task1(void)
{
register int reg_var = 1;
volatile int vol_var = 1;
SaveContext();
reg_var++;
vol_var++;
SaveContext();
reg_var++;
vol_var++;
LoadContext();
}
所以,当我在 gdb 中设置断点时,它不起作用,我认为它只会进入无限循环。我查看了初始化过程,是:
(gdb)
0x000082f6 in __libc_init_array ()
(gdb)
0x000080e2 in _start ()
(gdb)
0x000080e4 in _start ()
(gdb)
0x000080e6 in _start ()
(gdb)
main () at src/context-demo.c:12
12 int main(void) {
(gdb)
0x000081ea 12 int main(void) {
(gdb)
0x00000008 in ?? ()
(gdb)
0x0000000c in ?? ()
(gdb)
0x00000010 in ?? ()
(gdb)
0x00000014 in ?? ()
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000004 in ?? ()
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000004 in ?? ()
(gdb)
有人知道这里发生了什么吗?感谢任何帮助,谢谢!
如果你告诉 gdb 告诉你它正在执行的汇编指令,你会发现这更容易调试("display /3i $pc" 每次 gdb 停止时都会打印接下来的 3 条指令),并执行单步操作个别指令("stepi")。
某事导致您意外地以低地址 0x8 结束,您需要查明那是什么。要么你真的跳到 0x8,要么你采取了例外。查看每机器指令级别的执行会告诉您它是什么。
这里有一些似是而非的可能性:
- 可执行文件假设它有 RAM 而 realview-pb-a8 没有 RAM——这通常表现为 "writing to the stack (or global variables) silently does nothing and reading from the stack/globals returns 0",所以如果你在全局中有一个函数指针或者你试图推送一个 return 地址到堆栈然后弹出它你会在 0
- 可执行文件被构建为假设它是 运行 在提供 SVC API 的 OS 下——在这种情况下,代码将执行 SVC 指令并且您的代码将崩溃,因为有在 SVC 异常向量 没有什么可以处理的
- 为错误的 CPU 类型构建的可执行文件并执行 UNDEF 的指令(这应该导致执行地址 0x4,即 undef 向量,但我感觉它的 gdbstub 中有一个 qemu 错误可能意味着执行 UNDEF insn 的步骤将不会停止,直到在 UNDEF 向量处执行第一个 insn 之后)
- 构建的可执行文件假定 FPU 始终处于启用状态。当 QEMU 像这样执行 "bare metal" 二进制文件时,CPU 在硬件启动的状态下启动,其中 FPU 被禁用。因此,除非可执行文件的启动代码已明确打开 FPU,否则任何使用 FPU 的指令都将 UNDEF。
我已经按照您的案例的大致概率顺序列出了这些,但无论如何,机器指令的单步执行应该可以确定发生了什么。