커널 디버깅을 하다 보면 T32 simulator를 많이 쓰게 된다. 디버깅 과정에서 콜 스택을 보고 싶을 경우가 많다.
이번에 ARM Cortex A53 Call Stack 복원 방법을 정리하도록 하자.
T32 시뮬레이터의 가장 큰 장점은 각 프로세스 별로 Call Stack을 이쁘게 볼 수 있다는 점이다.
그런데 current process는 Call Stack을 제대로 볼 수 없다. 그 이유는 실행 도중 프로세스이기 때문에 Context(Register)정보를 Task Descriptor에
제대로 저장을 할 수 없기 때문이다.
magic___________|command_________|state_____|uid___|pid___|spaceid|tty_|flags___|cpu|
FFFFFFC001624860|swapper/0 |running | 0.| 0.| 0000 | 0 |00200000| 0.|
FFFFFFC00E690000|init |sleeping | 0.| 1.| 0001 | 0 |40400100| 3.|
FFFFFFC00E690AC0|kthreadd |sleeping | 0.| 2.| 0000 | 0 |00208040| 1.|
<생략>
FFFFFFC072900AC0|migration/7 |current(7)| 0.| 28.| 0000 | 0 |04208040| 7.|
FFFFFFC072901580|ksoftirqd/7 |sleeping | 0.| 29.| 0000 | 0 |04208040| 7.|
FFFFFFC072902B00|kworker/7:0H |sleeping | 0.| 31.| 0000 | 0 |04208060| 7.|
FFFFFFC0729035C0|khelper |sleeping | 0.| 32.| 0000 | 0 |04208060| 4.|
FFFFFFC072904080|netns |sleeping | 0.| 33.| 0000 | 0 |04208060| 4.|
FFFFFFC072904B40|perf |sleeping | 0.| 34.| 0000 | 0 |04208060| 4.|
"migration/7" 이놈 프로세스를 선택 후 우클릭을 해서 Call Stack을 보면 아래 화면과 같이 흐름이 깨져 나온다.
-000|__switch_to()
-001|degrade_zero_ticks(asm)
---|end of frame
그럼 이제 좀 시작해 볼까.
"migration/7" 이놈 프로세스의 Task Descriptor를 보자. 아래 stack 주소가 보인다.
(struct task_struct)*0xFFFFFFC072900AC0 = (
state = 0,
stack = 0xFFFFFFC07290C000,
usage = (counter = 3),
flags = 69238848,
ptrace = 0,
wake_entry = (next = 0x0),
on_cpu = 1,
아래 명령어로 스택 Base 주소로 접근하자. 64비트 ARM CortexA53 아키텍처의 스택 사이즈는 0x4000이다.
(참고로 ARM32 비트 아키텍처에서는 d.v %y.l [주소] 를 입력해야 함)
d.v %y.q 0xFFFFFFC07290C000+0x4000
________________address|_data____________________|value_____________|symbol
NSD:FFFFFFC07290BD78| A4 2A 29 00 C0 FF FF FF 0xFFFFFFC000292AA4 \vmlinuxwatchdog__touch_watchdog+0x1C
NSD:FFFFFFC07290BD80| 90 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BD90
NSD:FFFFFFC07290BD88| 6C 0B 25 00 C0 FF FF FF 0xFFFFFFC000250B6C \vmlinuxsched/clocksched_clock_cpu+0x1C
NSD:FFFFFFC07290BD90| A0 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BDA0
NSD:FFFFFFC07290BD98| 98 0B 25 00 C0 FF FF FF 0xFFFFFFC000250B98 \vmlinuxsched/clocklocal_clock+0x10
NSD:FFFFFFC07290BDA0| B0 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BDB0
NSD:FFFFFFC07290BDA8| A4 2A 29 00 C0 FF FF FF 0xFFFFFFC000292AA4 \vmlinuxwatchdog__touch_watchdog+0x1C
NSD:FFFFFFC07290BDB0| E0 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BDE0
NSD:FFFFFFC07290BDB8| BC 3D 24 00 C0 FF FF FF 0xFFFFFFC000243DBC \vmlinuxsmpbootsmpboot_thread_fn+0x118
NSD:FFFFFFC07290BDC0| C0 DE 8B 72 C0 FF FF FF 0xFFFFFFC0728BDEC0
NSD:FFFFFFC07290BDC8| 00 80 90 72 C0 FF FF FF 0xFFFFFFC072908000
NSD:FFFFFFC07290BDD0| E0 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BDE0
NSD:FFFFFFC07290BDD8| 50 3E 24 00 C0 FF FF FF 0xFFFFFFC000243E50 \vmlinuxsmpbootsmpboot_thread_fn+0x1AC
NSD:FFFFFFC07290BDE0| 30 BE 90 72 C0 FF FF FF 0xFFFFFFC07290BE30
NSD:FFFFFFC07290BDE8| 40 D3 23 00 C0 FF FF FF 0xFFFFFFC00023D340 \vmlinuxkthreadkthread+0xB0
NSD:FFFFFFC07290BDF0| 70 BC 69 0E C0 FF FF FF 0xFFFFFFC00E69BC70
NSD:FFFFFFC07290BDF8| 38 78 7F 01 C0 FF FF FF 0xFFFFFFC0017F7838 \vmlinuxkthreadkthread_create_lock
NSD:FFFFFFC07290BE00| 93 07 17 01 C0 FF FF FF 0xFFFFFFC001170793 \vmlinuxGlobalkallsyms_token_index+0x4A93
NSD:FFFFFFC07290BE08| C0 DE 8B 72 C0 FF FF FF 0xFFFFFFC0728BDEC0
NSD:FFFFFFC07290BE10| A4 3C 24 00 C0 FF FF FF 0xFFFFFFC000243CA4 \vmlinuxsmpbootsmpboot_thread_fn
NSD:FFFFFFC07290BE18| 00 00 00 00 00 00 00 00 0x0
NSD:FFFFFFC07290BE20| 00 00 00 00 00 00 00 00 0x0
NSD:FFFFFFC07290BE28| 24 D3 23 00 C0 FF FF FF 0xFFFFFFC00023D324 \vmlinuxkthreadkthread+0x94
위 스택 덤프에서 볼드체로 되어 있는 부분을 참고하자. 함수를 호출한 주소가 위치해있는 주소이다.
ARM CortexA53은 정말 함수 흐름을 잘 확인할 수 있는 Calling Convention인 것 같다. (Cortex A7은 좀 거시기 하지.)
그럼 가장 많은 정보를 볼 수 있는 Call Stack을 복원하기 위해 Stack을 0xFFFFFFC07290BD90, Program Counter를 0xFFFFFFC000250B6C로 지정해보자
________________address|_data____________________|value_____________|symbol
NSD:FFFFFFC07290BD78| A4 2A 29 00 C0 FF FF FF 0xFFFFFFC000292AA4 \vmlinuxwatchdog__touch_watchdog+0x1C
NSD:FFFFFFC07290BD80| 90 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BD90
NSD:FFFFFFC07290BD88| 6C 0B 25 00 C0 FF FF FF 0xFFFFFFC000250B6C \vmlinuxsched/clocksched_clock_cpu+0x1C
NSD:FFFFFFC07290BD90| A0 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BDA0
NSD:FFFFFFC07290BD98| 98 0B 25 00 C0 FF FF FF 0xFFFFFFC000250B98 \vmlinuxsched/clocklocal_clock+0x10
NSD:FFFFFFC07290BDA0| B0 BD 90 72 C0 FF FF FF 0xFFFFFFC07290BDB0
아래 명령어를 사용하자.
r.s sp 0xFFFFFFC07290BD90
r.s pc 0xFFFFFFC000250B6C
이후 v.f 명령어를 입력하여 콜 스택을 보면 아래와 같이 이쁘게 복원이 된다.
-000|sched_clock_cpu(cpu = ?)
-001|local_clock()
-002|get_timestamp(inline)
-002|__touch_watchdog()
-003|smpboot_thread_fn(data = 0xFFFFFFC0728BDEC0)
-004|smpboot_thread_fn(data = 0xFFFFFFC07290BE30)
-005|test_bit(inline)
-005|kthread(_create = 0x0)
---|end of frame
'시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리' 카테고리의 다른 글
ARM64(Aarch64) - 함수 호출시 Stack Push(스택 푸쉬) 규약 (0) | 2023.06.09 |
---|---|
ARM64- 스택 푸쉬(Stack Push) Userspace -> Kernel Space (0) | 2023.06.09 |
ARM64(Aarch64) - Special Register 설정(Trace32) (0) | 2023.06.09 |
ARM32- 스택 푸쉬(Stack Push) Userspace -> Kernel Space (0) | 2023.06.09 |
[Linux][ARM] char buf[32]; vs char buf[32]={0}; (0) | 2023.06.09 |