gdb: LoongArch: Improve loongarch_scan_prologue to record stack information
(1) Description of Problem:
When debugging the following code, the execution result of
nexti command is incorrect.
$ cat test.S
.text
.globl fun
.type fun, @function
fun:
or $r12,$r0,$r0
or $r4,$r12,$r0
jr $r1
.globl main
.type main, @function
main:
addi.d $r3,$r3,-16
st.d $r1,$r3,8
bl fun
or $r12,$r4,$r0
or $r4,$r12,$r0
ld.d $r1,$r3,8
addi.d $r3,$r3,16
jr $r1
$ gcc test.S -o test
$ gdb test
...
(gdb) set disassemble-next-line on
(gdb) start
...
Temporary breakpoint 1, 0x0000555555554754 in main ()
=> 0x0000555555554754 <main+8>:
57ffefff bl -20 # 0x555555554740 <fun>
(gdb) ni
0x0000555555554740 in fun ()
=> 0x0000555555554740 <fun+0>:
0015000c move $t0, $zero
(2) Root Cause Analysis:
In the internal execution flow of the ni command, a single-step will be
executed first. After that, it will enter process_event_stop_test (),
some conditions are judged in this function.
if ((get_stack_frame_id (frame)
!= ecs->event_thread->control.step_stack_frame_id)
&& get_frame_type (frame) != SIGTRAMP_FRAME
&& ((frame_unwind_caller_id (frame)
== ecs->event_thread->control.step_stack_frame_id)
&& ((ecs->event_thread->control.step_stack_frame_id
!= outer_frame_id)
|| (ecs->event_thread->control.step_start_function
!= find_pc_function (ecs->event_thread->stop_pc ())))))
{
...
if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL)
...
else
insert_step_resume_breakpoint_at_caller (frame);
}
Here, it will be judged whether a sub-function has been called based on
whether the frame id before the single step is not equal to the current
frame id and whether there is a calling relationship.
If a sub-function is called at this time and the current operation is nexti,
it will not stop immediately. Instead, insert_step_resume_breakpoint_at_caller()
will be called to complete the execution of the sub-function and then stop.
In above debugging examples, the executable program being debugged is compiled
from an asm source file that does not contain dwarf information. Therefore, the
frame id of the function is calculated by loongarch_frame_unwind rather than
dwarf2_frame_unwind. However, loongarch_scan_prologue() has not yet recorded
stack information in loongarch_frame_cache, this will cause problems in some
operations related to the frame id information.
(3) Solution:
Improve loongarch_scan_prologue() to record the stack information in
loongarch_frame_cache. And improve the loongarch_frame_unwind_stop_reason()
through the information recorded in loongarch_frame_cache.
(4) Test:
After this patch:
$ gdb test
(gdb) set disassemble-next-line on
(gdb) start
Temporary breakpoint 1, 0x0000555555554754 in main ()
=> 0x0000555555554754 <main+8>:
57ffefff bl -20 # 0x555555554740 <fun>
(gdb) ni
0x0000555555554758 in main ()
=> 0x0000555555554758 <main+12>:
0015008c move $t0, $a0
(gdb) ni
0x000055555555475c in main ()
=> 0x000055555555475c <main+16>:
00150184 move $a0, $t0
Signed-off-by: Hui Li <lihui@loongson.cn>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>