1. 程式人生 > >Qt可用的gdb編譯,以及交叉編譯gdbserver,以及配置QtCreator遠端除錯

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"