本文是在qemu-virt64-aarch64下運行smart-fetch的調試記錄
準備
編譯
按照userapps的readme進行編譯,編譯前鍵入如下命令,即可編譯出帶調試信息的userapps
xmake f --mode=debug
gdb配置
在調試過程中需要進入內核,所以需要同時加載內核和應用程序的elf符號表。設置.gdbinit文件如下:
target remote localhost:1234
file ../../../rt-thread/bsp/qemu-virt64-aarch64/rtthread.elf
add-symbol-file ../../apps/build/rootfs/bin/smart-fetch
首先使用readelf工具查看smart-fetch程序,發現其entry point是0x200000的_start,于是在gdb中打斷點b *0x200000(或b _start),在輸入smart-fetch后成功暫停
libc庫查看
本工程采用musl libc,可以自行下載查看源碼
調試記錄
以下按函數執行的順序來進行記錄
_start
該函數將當前用戶態棧指針設置為0xffff80000000,為用戶空間較高的地址,之后跳到_start_c
_start_c
所傳入的參數*p地址為smart預先設置的0xfffffffff000。這里存放了應用程序初始化所需的參數,由操作系統設置,最后調用傳參為__libc_start_main(main, 1, "/bin/smart-fetch",_init,_fini, 0 )
__libc_start_main
首先獲得程序的環境變量(操作系統設置,含有操作系統名稱,執行文件的信息等)
調用__init_libc(envp, "/bin/smart-fetch")
asm ( "" : "+r"(stage2) : : "memory" )表示保證在之后stage2采用更新后的值,避免使用緩存的值
__init_libc
該函數前面主要是通過envp來獲取一些程序信息如pagesize等,接下來執行__init_tls和__init_ssp
__init_tls
該函數目的是初始化線程局部存儲(thread local storage)。它需要根據elf文件的類型為PT_TLS的段來對線程局部存儲進行初始化。這里由于smart-fetch不是多線程程序,沒有PT_TLS類型的段,故該函數在這里沒有進行實際的操作。
__init_ssp
該函數是初始化棧保護機制,但這里并未實現該機制。執行dummy函數,不做任何操作
libc_start_main_stage2
首先執行__libc_start_init進行初始化
之后調用main函數獲取返回值
之后調用exit(main_ret)來進行清理
__libc_start_init
調用事先注冊好的初始化函數列表__init_array_start。
本處調用了frame_dummy函數,該函數并不是musl庫里的函數,而是gcc編譯時插入的函數。該函數調用初始化函數(即定義了__attribute__((constructor))的函數),并調用register_tm_clones來注冊多線程下的克隆函數。因為這個程序無初始化函數和多線程的特性,所以該函數實際上并未執行任何操作。
exit
__funcs_on_exit:無操作
__libc_exit_fini:該函數對應于__libc_start_init,調用解構函數,注銷多線程克隆函數,在這里也沒有實質性的操作
_stdio_exit:關閉所有打開文件及標準輸入、輸出、錯誤文件
_Exit:調用SYS_exit_group系統調用,之后就是操作系統進行資源回收
缺頁異常處理
當訪問一個不存在頁時,aarch改變的寄存器
sp 0xffff80000000 -> 0xffff0000002b6520
pc 0x20008 -> 0xffff0000000c6400
cpsr 0 -> 0x3c5
elr_el1 0x200000 -> 0x200008
sp_el0 0 -> 0xffff80000000
ESR_EL1 0-> 0x92000045
FAR_EL1 0 -> 0xffff7fffffd0
aarch64自動做的事(通過對比缺頁觸發前后寄存器值得出):
-
寄存器
+關注
關注
31文章
5363瀏覽量
120921 -
存儲器
+關注
關注
38文章
7526瀏覽量
164165 -
RT-Thread
+關注
關注
31文章
1305瀏覽量
40302 -
GDB調試
+關注
關注
0文章
24瀏覽量
1471
發布評論請先 登錄
相關推薦
評論