Qt可用的gdb編譯,以及交叉編譯gdbserver,以及配置QtCreator遠程調試

項目中用了ARM的板,希望配置gdbserver進行遠程調試,結果卻遇到了很多問題。先把坑說了:

1)要支持遠程調試,arm板需要支持ssh

2)要gdb能在Qt上用,必須在configure gdb的時候使用--with-python選項啓用python支持

3)需要安裝python-dev(2.7的包,不是3的),但是即使裝了也可能鏈接失敗,報PyUnicodeUCS2_????函數沒有找到,需要define Py_UNICODE_WIDE

4)要成功啓動遠程調試,gdb和gdbserver必須是同一份源碼編譯出來的,而且make install之後的share目錄也是必須的,否則gdb就不能正常啓動


步驟一:編譯gdb

python支持是gdb自帶的,但是默認不開啓,而python支持是Qt要求的,所以configure的時候使用--with-python將python支持打開,具體命令如下:

./configure CFLAGS="-O3" CXXFLAGS="-O3" --target=arm-linux --prefix=/opt/arm-linux-gdb/ --with-python     ————————命令(1)

這裏--target後面是交叉編譯工具鏈的前綴,比如交叉編譯工具鏈的gcc是arm-linux-gcc,那就是arm-linux,--prefix是make install的目錄。另外加了-O3增強了編譯優化,而且沒有了-g,取消了調試信息的生成。

但是configure之後make卻可能報PyUnicodeUCS2_????函數沒有找到的鏈接錯誤,這是因爲python-dev的庫裏的函數是PyUnicodeUCS4_????。在include/python-2.7/unicodeobject.h里根據是否有定義Py_UNICODE_WIDE,將PyUnicode_???定義爲PyUnicodeUCS2_????或PyUnicodeUCS4_????。但是,unicodeobject.h用的可能是交叉編譯工具鏈目錄下的文件,而不是python-dev包裏的文件,所以直接改文件並不好,既然知道是根據否有定義Py_UNICODE_WIDE控制的函數名,在CFLAGS和CXXFLAGS中使用-D選項定義Py_UNICODE_WIDE就好了。所以,命令變爲

./configure CFLAGS="-DPy_UNICODE_WIDE -O3" CXXFLAGS="-DPy_UNICODE_WIDE -O3"  --target=arm-linux --prefix=/opt/arm-linux-gdb/ --with-python     ————————命令(2)

如果沒報鏈接錯誤,那麼so中的函數就是PyUnicodeUCS2_????的了。如果需要先判斷python-dev裏的函數到底是2還是4,不想出錯之後再來折騰,就需要找到libpython2.7.so的絕對路徑,然後使用nm -D ???/libpython2.7.so | grep PyUnicode來查看so中的函數名是2還是4了。我在Ubuntu 14.04中的路徑是/usr/lib/x86_64-linux-gnu/libpython2.7.so。

文末給出了完整的編譯腳本,腳本是通過輸出一個check.c,編譯後執行,程序使用dlopen打開libpython2.7.so,並且嘗試獲取PyUnicodeUCS4_Decode的函數地址,如果能拿到就代表so的函數名是4,否則就是2。

建議使用make -j4或者-j8進行併發編譯,雖然GDB的源碼包不大(8.1的是37M),但是編譯卻需要出奇長的時間。make完之後make install,可以在/opt/arm-linux-gdb看到gdb的程序


步驟二:編譯gdbserver

編譯gdbserver,先切換目錄到gdb/gdbserver,然後使用如下命令configure:

./configure CFLAGS="-O3" CXXFLAGS="-O3" --target=arm-linux --prefix=/opt/arm-linux-gdb/ --host=arm-linux  ----命令(3)

這裏多了--host,代表gdbserver是在arm中運行的。configure之後可以make -j4和make install,沒什麼坑。最後arm-linux-gdbserver也是放到/opt/arm-linux-gdb/bin中,改名爲gdbserver。


步驟三:建議壓縮編譯出來的可執行文件

切換到/opt/arm-linux-gdb/bin中,執行如下語句壓縮可執行文件:

strip arm-linux-gdb arm-linux-run   ----命令(4)
arm-linux-strip gdbserver           ----命令(5)

strip是gcc套裝裏的一個工具,肯定有的,壓縮運行在本地的arm-linux-gdb和arm-linux-run,arm-linux-strip在交叉編譯工具鏈裏,壓縮運行在arm環境裏的gdbserver。


步驟四:將新的gdb和gdbserver放入交叉編譯工具鏈

這一步,將/opt/arm-linux-gdb/bin中arm-linux-gdb和arm-linux-run都拷貝到交叉編譯工具鏈的bin目錄,然後重點是要將/opt/arm-linux-gdb/share的內容也拷貝放入交叉編譯工具鏈的share目錄,否則gdb無法運行。然後下載gdbserver到arm系統的/usr/bin目錄,gdbserver就成了命令可以直接運行了,不需要用/usr/bin/gdbserver或者./gdbserver來運行,或者設置鏈接了。


步驟五:配置QtCreator

首先配置調試器,找到新編譯出來的arm-linux-gdb:


然後是配置構建套件,在調試器裏選剛纔配置的調試器名稱


配置arm板的設備,確保arm板支持ssh,填好信息之後點test看看能不能連上


然後就可以開始調試了


最後給出完整的編譯腳本,將gdb源碼解壓出來,把腳本放進去,使用chmod 777設置好權限,一鍵做完全部步驟,當然配置QtCreator還是要自己做的。編譯腳本的make install目錄就是/opt/arm-linux-gdb,交叉編譯工具鏈的前綴是arm-linux,如果需要自定義的可以自己改。腳本的提示綠色是成功,紅色是失敗,黑色是其他的輸出出問題再看吧。

#!/bin/bash
echo -e "\033[32m 正在執行步驟一:檢查python-dev包 \033[0m"
chkpydev=$(dpkg -l | grep python-dev)
if [ "$chkpydev" == "" ]; then
	sudo apt-get install python-dev --force-yes
fi

echo "#include <stdio.h>" > check.c
echo "#include <dlfcn.h>" >> check.c
echo "int main() { void *handle; void *pPyUnicodeUCS4_Decode = NULL; handle = dlopen(\"libpython2.7.so\", RTLD_LAZY); if (!handle)return 1; dlerror(); pPyUnicodeUCS4_Decode = dlsym(handle, \"PyUnicodeUCS4_Decode\"); if (dlerror() != NULL)return 2; dlclose(handle); return 3; }" >> check.c
gcc -rdynamic -o check check.c -ldl && ./check
checkpy=$?
rm check
rm check.c

echo -e "\033[32m 正在執行步驟二:gdb的configure \033[0m"
case $checkpy in
    1)
	echo "沒有找到libpython2.7.so"
	exit
    ;;
    2)
	./configure CFLAGS="-O3" CXXFLAGS="-O3" --target=arm-linux --prefix=/opt/arm-linux-gdb/ --with-python
    ;;
    3)
	./configure CFLAGS="-DPy_UNICODE_WIDE -O3" CXXFLAGS="-DPy_UNICODE_WIDE -O3" --target=arm-linux --prefix=/opt/arm-linux-gdb/ --with-python
    ;;
esac

echo -e "\033[32m 正在執行步驟三:編譯和安裝gdb \033[0m"
make -j8
if [ $? -eq 0 ]; then
    make install
    echo -e "\033[32m gdb已安裝到/opt/arm-linux-gdb/目錄下 \033[0m"
else
    echo -e "\033[31m gdb編譯失敗 \033[0m"
    exit
fi

echo -e "\033[32m 正在執行步驟四:gdbserver的confiure \033[0m"
cd gdb/gdbserver
./configure CFLAGS="-O3" CXXFLAGS="-O3" --target=arm-linux --prefix=/opt/arm-linux-gdb/ --host=arm-linux
 
echo -e "\033[32m 正在執行步驟五:編譯和安裝gdbserver \033[0m"
make -j8
if [ $? -eq 0 ]; then
    make install
    echo -e "\033[32m gdbserver已安裝到/opt/arm-linux-gdb/目錄下 \033[0m"
else
    echo -e "\033[31m gdbserver編譯失敗 \033[0m"
    exit
fi

echo -e "\033[32m 正在執行步驟六:壓縮可執行文件,將gdb放入交叉編譯工具鏈 \033[0m"
cd /opt/arm-linux-gdb/bin/
cp arm-linux-gdbserver gdbserver
arm-linux-strip gdbserver
echo "arm-linux-strip gdbserver"
strip arm-linux-gdb arm-linux-run
echo "strip arm-linux-gdb arm-linux-run"
gdb_path=$(which arm-linux-gdb)
cross_path=${gdb_path%/*}/..
mv $(which arm-linux-gdb) $cross_path/bin/arm-linux-gdb.bk
echo "mv $cross_path/bin/arm-linux-gdb $cross_path/bin/arm-linux-gdb.bk"
cp arm-linux-gdb $cross_path/bin
echo "cp arm-linux-gdb $cross_path/bin"
mv $(which arm-linux-run) $cross_path/bin/arm-linux-run.bk
echo "mv $cross_path/bin/arm-linux-run $cross_path/bin/arm-linux-run.bk"
cp arm-linux-run $cross_path/bin
echo "cp arm-linux-run $cross_path/bin"
cd ..
cp -rf share $cross_path
echo "cp -rf share $cross_path"
echo -e "\033[32m 已經將新的arm-linux-gdb放入交叉編譯工具鏈目錄$cross_path/bin \033[0m"
echo -e "\033[32m 完成 \033[0m"


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章