嵌入式GDB除錯Linux C程式或交叉編譯(開發板)

舟清颺發表於2024-07-02

目錄
  • 簡介
  • 開始使用
    • 電腦端
      • 準備
        • 安裝gdb
        • 1.編譯帶除錯資訊的可執行檔案
        • 2.進入gdb
        • 3.啟動程式
      • 常用命令
        • 設定斷點:
        • 進入函式
        • 列印數值
        • 結束
  • 常用命令
    • l
    • Enter鍵
    • b
    • C
    • S
    • n
    • p
    • q
    • 參考文件
    • 1、安裝gdb。
    • 2、gdb的簡單使用。
      • (1) 在可執行檔案中加入原始碼資訊
      • (2) 進入gdb
      • (3) gdb除錯常用命令
        • [1] start
        • [2] 單步執行(n)
        • [3] gdb斷點除錯
        • [7] gdb的觀察點(watch 和c)
        • [8] 段錯誤
        • [9] gdb基本命令
  • 開發板移植-自行編譯(作廢)
    • 獲取 gdb和 gdbserver原始碼
    • 編譯 gdb
  • 開發板移植-自行編譯(成功)
    • 下載可用的編譯器
      • 下載
      • 安裝
      • 使用
    • GDB移植到開發板
    • 編譯可除錯的程式
  • gdb+gdbserver除錯程式
      • 傳輸可執行檔案到開發板
      • 執行程式
  • VSCode+gdbserver圖形化除錯
    • VSCode設定
    • VSCode除錯方法
  • 依賴環境搭建
    • LVGL-freeType字型
    • 設定中文字型
  • 參考文件

更新日誌:

v1.2 2024年6月24日19:59:19 基本文件編寫 2024年7月2日釋出於部落格園

簡介

gdb工具是 GNU專案偵錯程式,基於命令列。和其他的偵錯程式一樣,我們可以使用 gdb來一行行的執行程式、單步執行、跳入 /跳出函式、設定斷點、檢視變數等等,它是 UNIX/LINUX作業系統下強大的程式除錯工具。 gdb支援多種語言,包括 Ada、彙編、 C/C++、 D、 Fortran、 GO、Objective-C、 OpenCL、 Modula-2、 Pascal和 Rust。關於 gdb更多詳細的資訊請到 gdb官網查閱,gdb官網地址為: www.gnu.org。
一般的桌面 Linux系統,比如 ubuntu、 centos等,我們可以直接執行 gdb來除錯程式。但是嵌入式中晶片效能一般比較弱,所以直接在嵌入式系統中執行 gdb不太現實 (效能強大的嵌入式晶片可以這麼做 )。嵌入式系統中一般在 PC端執行 gdb工具,原始碼也是在 PC端,原始碼應的可執行檔案放到開發板中執行。為此我們需要在開發板中執行 gdbserver,透過網路與 PC端的 gdb進行通訊。因此要想在 PC上透過 gdb除錯嵌入式程式,那麼需要兩個東西: gdb和gdbserver,其中 gdb是執行在 PC上的, gdbserver需要我們移植到開發板上。

開始使用

開發板要和上位機處於同一區域網!!

開發板要和上位機處於同一區域網!!

開發板要和上位機處於同一區域網!!

重要的事情說三遍!

電腦端

準備

安裝gdb

在root使用者許可權下:

root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get update
root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get install gdb 
Do you want to continue? [Y/n] y

1.編譯帶除錯資訊的可執行檔案

使用編譯命令 -g 例如:

-g選項的作用是:在可執行檔案中加入原始碼資訊,比如:可執行檔案中第幾條機器指令對應原始碼的第幾行,但並不是把整個原始檔都嵌入到可執行檔案中,而是在除錯時必須保證gdb能找到原始檔。

cc client.c cJSON.c myJSON.c base64.c -g -o client.out  -pthread

2.進入gdb

gdb client.out

這時候gdb環境準備就緒, 會有歡迎介面, 按一下Enter鍵, 開始進入命令輸入

3.啟動程式

start

這時候程式啟動,但等待你的下一步操作, 可以設定斷點等

常用命令

在start以後

設定斷點:

b 124 #在第124行設定斷點, 然後繼續
c #讓程式執行到設定的斷點 124 行停下. 這裡的行數是你的main.c的行數
n #單步執行: 讓程式一次執行一行, 注意不會入子函式模組!! 只會顯示函式執行結果,例如第124行是呼叫函式, 則應該c 124, 讓程式在124停止

進入函式

step #在上面的設定斷點到 124行的函式呼叫時 , 進入到124行的函式內部
n #繼續在函式內部按行執行, 是可以繼續設定斷點的. 

列印數值

display count#display可以將變數count新增到監聽佇列, 監聽佇列的值會被顯示列印出來
undisplay 3#將監聽佇列中的第三號成員移除佇列

結束

quit #退出gdb! !!!!注意不可以ctrl+C結束程式, 會導致異常!!!!! 會導致異常!!!!

常用命令

l

是L的小寫

l命令 (list)用於列出所有程式原始碼,輸入“ l”

輸入“ l”命令以後就列印出了除錯程式的所有原始碼,如果原始碼沒有列印完的話就重複按下“ l”命令,或者按下Enter鍵, gdb除錯工具中Enter鍵表示重複上一個命令!

Enter鍵

重複上一個命令

b

b命令 (break)用於設定斷點,也可以用縮寫“ b”,後面可以跟具體的函式或者行號,比如break main”表示在 main函式處設定斷點,“ break 11”在第 11行設定斷點。

b 11 #在第 11行設定斷點
b main #在 main函式處設定斷點

C

命令用於執行到斷點 處 ,輸入 c命令程式就會執行,直到下一個斷點處(該斷點只會作用一次). 再次c就會繼續往下, 若沒有斷點就會繼續執行, 直到程式結束.

S

s命令 (step)是單步執行執行,此函式會進入到函式里面。

n

n命令 (next)也是單步執行,但是 n命令不會進入到函式里面。

p

p命令 (print)用於列印某個變數值。

q

q命令 (quit)用於退出除錯,開發板上的 gdbserver也會停止。

參考文件

1、安裝gdb。

在root使用者許可權下:

root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get update
......
......
......
root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get install gdb 
......
......
......
Do you want to continue? [Y/n] y
......
......
......
root@iZ2zeeailqvwws5dcuivdbZ:~# 

安裝好gdb了。

2、gdb的簡單使用。

用root許可權的Terminal(或一般許可權的Terminal)的vi編輯器編寫一個C程式a.c:

1 #include <stdio.h>
2 
3 int main()
4 {
5   int a = 1;
6   int b = a;
7 
8   printf("a = %d, b =%d\n", a, b);
9 
10   return 0;
11 }

(1) 在可執行檔案中加入原始碼資訊

這個過程透過gcc來完成:

gcc –o a a.c -g

-o選項的作用是:對命令輸出結果進行匯入操作,這裡是把gcc –o a a.c -g的操作結果輸出到檔案a(檔名可以自定義)中進行儲存。

-g選項的作用是:在可執行檔案中加入原始碼資訊,比如:可執行檔案中第幾條機器指令對應原始碼的第幾行,但並不是把整個原始檔都嵌入到可執行檔案中,而是在除錯時必須保證gdb能找到原始檔。

(2) 進入gdb

root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gcc -o a a.c -g
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a...done.
(gdb) 

如下圖所示:

image

gdb提供一個類似Shell的命令列環境,上面的(gdb)就是提示符,在提示符後面輸入gdb的相應命令就可以實現其對應的功能。

(3) gdb除錯常用命令

[1] start

  用start命令開始執行程式:

(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) 

  gdb提示準備執行a.c程式的第六行程式碼。然後繼續用(gdb)提示需要輸入的命令。

[2] 單步執行(n)

(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) n
6           int b = a;
(gdb) n
8           printf("a = %d, b = %d\n", a, b);
(gdb) n
a = 1, b = 1
9           return 0;
(gdb) quit
A debugging session is active.

   Inferior 1 [process 22935] will be killed.

Quit anyway? (y or n) y
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# 

  在start命令後,每輸入一個n就能夠單步執行一條語句(輸入一個命令後,直接回車表示最近輸入命令的含義)。當程式執行完時,可以輸入quit命令來退出gdb模式。

[3] gdb斷點除錯

  [ breakpoint,*continue和*display ]

(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) b 8
Breakpoint 2 at 0x40053b: file a.c, line 8.
(gdb) c
Continuing.

Breakpoint 2, main () at a.c:8
8           printf("a = %d, b = %d\n", a, b);
(gdb) display b
1: b = 1
(gdb) n
a = 1, b = 1
9           return 0;
1: b = 1
(gdb) 
10      }
1: b = 1
(gdb) quit
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# 

  gdb a會進入a可執行程式的gdb模式,start命令就使程式準備執行程式中的第一條語句。b 8是breakpoint 8的簡寫(breakpoint的引數也可以以是某個函式名,表示在此函式處設定一個斷點),表示在程式第八行設定一個斷點。c是continue的縮寫,表示繼續執行程式,程式會在設定斷點處停下來。displayb表示將b的值顯示出來(undisplay取消對變數的跟蹤),然後再輸入單步除錯命令n(next)就可以使程式繼續執行。

  可見斷點有助於快速跳過沒有問題的程式碼,然後在有問題的程式碼上慢慢走慢慢分析,“斷點加單步”是使用偵錯程式的基本方法。至於應該在哪裡設定斷點,怎麼知道哪些程式碼可以跳過,而哪些程式碼要慢慢走,也要透過對錯誤現象的分析和假設來確定,以前我們用printf列印中間結果時,也要分析應該在哪裡插入printf,列印哪些中間結果,除錯的基本思路是一樣的。

  [4]*info*

  一次除錯可以設定多個斷點,用info命令可以檢視已經設定的斷點:

root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a...done.
(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) b 7
Breakpoint 2 at 0x40053b: file a.c, line 7.
(gdb) b 8
Note: breakpoint 2 also set at pc 0x40053b.
Breakpoint 3 at 0x40053b: file a.c, line 8.
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040053b in main at a.c:7
3       breakpoint     keep y   0x000000000040053b in main at a.c:8
(gdb) 

  [5]*delete*

  每個斷點都有一個編號(有的斷點行數不一樣,但地址卻一樣,有的地方不能夠設定斷點或者說與上一個設定的斷點等效),可以用編號指定刪除某個斷點。

......(gdb) b 7
Breakpoint 2 at 0x40053b: file a.c, line 7.
(gdb) b 8
Note: breakpoint 2 also set at pc 0x40053b.
Breakpoint 3 at 0x40053b: file a.c, line 8.
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040053b in main at a.c:7
3       breakpoint     keep y   0x000000000040053b in main at a.c:8
(gdb) delete 3
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040053b in main at a.c:7
(gdb) 

  有時候一個斷點暫時不用可以禁用掉而不必刪除,這樣以後想用的時候可以直接啟用,而不必重新從程式碼裡找應該在哪一行設斷點,這個過程用 disable 和 enable 來完成。

  [6]*條件斷點 (break 和run)*

  gdb的斷點功能非常靈活,還可以設定斷點在滿足某個條件時才啟用,例如:

......//先把其餘的斷點刪掉。(gdb) b 9 if a == 2
Breakpoint 5 at 0x400552: file a.c, line 9.
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
5       breakpoint     keep y   0x0000000000400552 in main at a.c:9
   stop only if a == 2
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/2/02/a 
a = 1, b = 1
[Inferior 1 (process 22968) exited normally]
(gdb) 

  r表示從頭開始執行程式,在a==2的條件下中斷才有效。a不等於2,所以中斷無效。  

[7] gdb的觀察點(watch 和c)

  斷點是當程式執行到某一程式碼行時中斷,而觀察點是當程式訪問某個儲存單元時中斷,如果我們不知道某個儲存單元是在哪裡被改動的,這時候觀察點尤其有用。

root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a...done.
(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) watch b
Hardware watchpoint 2: b
(gdb) c
Continuing.

Hardware watchpoint 2: b

Old value = 0
New value = 1
main () at a.c:8
8           printf("a = %d, b = %d\n", a, b);
(gdb) 

  程式執行到b儲存單元,將此執行單元執行前後的值都顯示出來。

[8] 段錯誤

  如果程式執行時出現段錯誤,用gdb可以很容易定位到究竟是哪一行引發的段錯誤。在gdb中執行,遇到段錯誤會自動停下來,這時可以用命令檢視當前執行到哪一行程式碼了。

  gdb顯示段錯誤出現在 _IO_vfscanf 函式中,用bt命令可以看到是哪一個函式呼叫了它。

[9] gdb基本命令

  gdb有許多有用的命令如list(顯示原始碼),這樣就可以結合原始碼與除錯資訊更好的進行除錯。將gdb常用命令摘抄如下表:

命令 描述
backtrace(bt) 檢視各級函式呼叫及引數
finish 連續執行到當前函式返回為止,然後停下來等待命令
frame(f) 幀編號 選擇棧幀
info(i) locals 檢視當前棧幀區域性變數的值
list(l) 列出原始碼,接著上次的位置往下列,每次列十行
list 行號 列出第幾行開始的原始碼
list 函式名 列出某個函式的原始碼
next(n) 執行下一行語句
print(p) 列印表示式的值,透過表示式的值可以修改變數的值或者呼叫函式
quit(q) 退出gdb除錯環境
set var 修改變數的值
start 開始執行程式,停在main函式第一行語句前面等待命令
step(s) 執行下一行語句,如果有函式則進入到函式中
break(b) 行號 在某一行設定斷點
break 函式名 在某個函式開頭設定斷點
break(b)… if… 設定條件斷點
continue(c) 從當前位置開始連續執行程式
delete breakpoints 斷點號 刪掉此號的斷點
display 變數名 跟蹤檢視某個變數,每次停下來都顯示它的值
disable breakpoints 斷點號 禁用此斷點
enable 斷點號 啟用此斷點
info(i) breakpoints 檢視當前設定了哪些斷點
run(r) 從頭開始連續執行程式
undisplay 跟蹤顯示行號 取消跟蹤顯示
watch 設定觀察點
info(i) watchpoints 檢視當前設定了哪些觀察點
x 從某個位置開始列印儲存單元的內容,全部當成位元組來看,而不區分哪個位元組屬於哪個變數
disassemble 反彙編當前函式或者指定的函式,單獨用disassemble命令是反彙編當前函式,如果disassemble命令後面跟函式名或地址則反彙編指定的函式。
si 可以一條指令一條指令地單步除錯。
info registers 可以顯示所有暫存器的當前值。在gdb中表示暫存器名時前面要加個$,例如p $esp可以列印esp暫存器的值。
set follow-fork-mode child/parent 設定gdb在fork之後跟蹤子程序/父程序
set args 'command-line' 給執行的程式傳命令列引數
s(stepin) 進入子函式

開發板移植-自行編譯(作廢)

適用於編譯器沒有自帶gdb, 需要編譯.

2024年6月24日: 嘗試編譯失敗, 使用 的5.4.0交叉編譯器, 無法生成gdb, 懷疑是編譯器不完全, 解決方法: 更換編譯器.

獲取 gdb和 gdbserver原始碼

開發板配套預設的編譯器沒有gdb因此需要自己編譯

首先到 gdb官網上獲取原始碼,地址為 https://www.gnu.org/software/gdb/download/在筆者寫本教程的時候,最新的 gdb原始碼 版本 為 9.1。已經放到了開發板光碟中,路徑為: 1、例程原始碼->7、第三方庫原始碼 -> gdb-9.1.tar.gz。將 gdb原始碼傳送到 ubuntu中 中並解壓,命令如下:

Index of /pub/gdb/releases (sourceware.org)

以root賬戶執行:

cd /root
mkdir gdb 
mkdir /DevelopmentTool/gdb#存放編譯後可執行的gdb
#將檔案放入 gdb資料夾中,臨時存放
root@yuyi-machine:~/gdb# tar -vxzf gdb-9.1.tar.gz//解壓 gdb原始碼
root@yuyi-machine:~/gdb# ls
gdb-9.1  gdb-9.1.tar.gz

解壓完成以後就會得到一個名為 gdb-9.1的資料夾,此資料夾就是 gdb和 gdbserver原始碼,其中 gdb-9.1/gdb/gdbserver目錄就是 gdbserver原始碼。

編譯 gdb

1、編譯 gdb
首先編譯 gdb gdb是執行在 PC端的程式, gdb編譯的時候需要進行配置,配置項如下:

--target 目標機交叉編譯器字首,也就是你所使用的交叉編譯器字首,比如在本教程中就設定為 arm-linux-gnueabihf。
--host 指定編譯後的程式在哪裡執行,編譯 gdb的時候就需用設定,因為我們是需要在 PC上執行的,編譯 gdbserver的時候就要設定為 arm-linux。
--prefix 指定安裝目錄。
建立一個名為“gdb”的資料夾,用來儲存編譯後的 gdb和 gdbserver,路徑自行選擇。 gdb編譯比較奇葩!使用如下命令配置並編譯 gdb: 


cd gdb-9.1/ 	//進入 gdb原始碼目錄
mkdir build 	//在 gdb原始碼下新建 build目錄, gdb編譯比較奇葩!不能直接在 gdb源
				//碼目錄下進行配置和編譯,必須新建一個資料夾,然後在此資料夾下配置和編譯,切記!
cd build //進入到剛剛建立的 build目錄下
../configure --target=arm-linux-gnueabihf --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/gdb 
				//配置 gdb。配置完成以後會在 build目錄下生成 Makefile檔案。
make //編譯
make install //安裝

執行例項:

root@yuyi-machine:~/gdb# ls
gdb-9.1  gdb-9.1.tar.gz
root@yuyi-machine:~/gdb# cd gdb-9.1/
root@yuyi-machine:~/gdb/gdb-9.1# mkdir build
root@yuyi-machine:~/gdb/gdb-9.1# cd build
root@yuyi-machine:~/gdb/gdb-9.1/build# ../configure --target=arm-linux --prefix=/DevelopmentTool/gdb
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking target system type... arm-unknown-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
********
********
make 
make[4]: *** [Makefile:490: gdb.info] Error 127
make[4]: Leaving directory '/root/gdb/gdb-9.1/build/gdb/doc'
make[3]: *** [Makefile:2006: subdir_do] Error 1
make[3]: Leaving directory '/root/gdb/gdb-9.1/build/gdb'
make[2]: *** [Makefile:1651: all] Error 2
make[2]: Leaving directory '/root/gdb/gdb-9.1/build/gdb'
make[1]: *** [Makefile:9564: all-gdb] Error 2
make[1]: Leaving directory '/root/gdb/gdb-9.1/build'
make: *** [Makefile:852: all] Error 2
root@yuyi-machine:~/gdb/gdb-9.1/build#
########################這裡之後就報錯了, 具體不清楚,

make install



root@yuyi-machine:~/gdb/gdb-9.1/build# cd /DevelopmentTool/gdb/
root@yuyi-machine:/DevelopmentTool/gdb# ls
bin  lib  share

編譯完成以後 PC端執行的 gdb工具就會安裝到 gdb/bin目錄下,名字為 arm-linux-gnueabihf-gdb,如圖 B3.2.2.1所示:

########################這裡之後就報錯了, 具體不清楚,

開發板移植-自行編譯(成功)

下載可用的編譯器

下載

Linaro Releases

image

板子應該下載x86_64的版本, 因為開發平臺是64位的linux. 應該不要下載帶h的, h表示硬浮點, 因為 的板子的Linux檔案系統中的庫都是使用軟浮點模式編譯的.

官方給的5.4.0版本不完全, 使用很多庫會報錯! 要修改的有很多. 故推薦5.4.1

安裝

sudo apt-get install lsb-core lib32stdc++6 #安裝其它的庫

在電腦的Linux系統中切換為root使用者

su - #切換root
cd /
mkdir /DevelopmentTool/ #建立資料夾
# 然後將 下載好的 gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi.tar.xz 上傳到其中
tar -vxf gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi.tar.xz #解壓
cd /etc/profile.d #進入全域性指令碼資料夾
touch IoT_development.sh #建立自定義指令碼檔案 
chmod 644 IoT_development.sh
vim IoT_development.sh
# 修改環境變數, 加入下面的內容即可
export PATH=/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/bin:$PATH
# 重啟系統或 
source ./IoT_development.sh
# 檢視版本號  如果交叉編譯器安裝正確的話就會顯示版本號,如圖
arm-linux-gnueabi-gcc -v
# 若沒有生效, 需要每個使用者在終端手動執行下面命令, 或設定另一個全域性變數指令碼檔案
echo "export PATH=/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/bin:$PATH"  >>  ~/.bashrc
source ~/.bashrc
arm-linux-gnueabi-gcc -v

使用

# 終端直接編譯
arm-linux-gnueabi-gcc main.c -o demo.out
# Makefile編寫
CC = arm-linux-gnueabi-gcc

若有多個不同版本的交叉編譯鏈, 使用時使用完整的名稱即可.

若有需要,程式相關的依賴環境,需要自己補上.

GDB移植到開發板

到了這一步, 編譯器已經可以用gdb, 但是開發板不支援

image

檢視編譯器筆記, 下載新交叉編譯器gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi.tar.xz

編譯可除錯的程式

使用 arm-linux-gnueabi-gcc交叉編譯 demo.c檔案,要想除錯程式,那麼編譯的時候必須加上“ “-g”選項,這樣編譯出來的可執行檔案才

帶有除錯資訊,這一點一定要切記!編譯命令如下所示:

arm-linux-gnueabi-gcc demo.c -o demo.out -g //編譯測試程式,注意 -g選項

編譯完成以後將得到的 demo.out可執行檔案傳送到開發板中。

gdb+gdbserver除錯程式

一切準備就緒以後就可以使用 GDB進行除錯了,確保 ubuntu和開發板可以進行網路通訊。
開發板中輸入如下命令:

下面以客戶端 arm-linux-gnueabi-gcc client.c -o client.out -g -pthread 做示範

編譯程式:

yuyi@yuyi-machine:~/workspace/zqingyangLib/examples/2024年6月21日_檔案傳輸/temple$  arm-linux-gnueabi-gcc client.c -o client.out -g  -pthread 
yuyi@yuyi-machine:~/workspace/zqingyangLib/examples/2024年6月21日_檔案傳輸/temple$ file client.out 
client.out: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=0fe128394b46c30aa29bc8c4ee4914f35b7305e4, with debug_info, not stripped

傳輸可執行檔案到開發板

然後將檔案傳輸到開發板,

執行程式

在開發板上輸入:

gdbserver 192.168.64.202:2001 ./client.out //啟動開發板上的 gdbserver
#gdbserver <上位機(除錯機)的IP>:<自定義通訊埠號> <要除錯的可執行檔案,例如./client.out>

結果

[root@GEC6818 /yuyiworkspace/tmp]#chmod 777 client.out
[root@GEC6818 /yuyiworkspace/tmp]#gdbserver 192.168.64.202:2001 ./client.out
Process ./client.out created; pid = 1516
Listening on port 2001

上位機(除錯機)中輸入如下命令啟動 gdb除錯工具:

這裡的./client.out是你要調的程式在上位機的位置, 也就是兩邊都要有 !!!

arm-linux-gnueabi-gdb  ./client.out #這裡的./client.out是你要調的程式在上位機的位置, 也就是兩邊都要有

結果

yuyi@yuyi-machine:~/workspace/zqingyangLib/examples/2024年6月21日_檔案傳輸$ arm-linux-gnueabi-gdb  ./client.out
GNU gdb (Linaro_GDB-2017.01) 7.12.1.20170127-git
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-linux-gnueabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...

上位機: 連線開發板

target remote 192.168.64.203:2001 #連線到開發板上
#target remote <開發板地址>:2001

連線成功以後開發板中的 gdbserver就會提示連線資訊, 下面是開發板的終端輸出:

[root@GEC6818 /yuyiworkspace/tmp]#gdbserver 192.168.64.202:2001 ./client.out
Process ./client.out created; pid = 1516
Listening on port 2001
Remote debugging from host 192.168.64.202

可以看出,遠端除錯機的 IP地址為 192.168.64.202,也就是我們的上位機地址,連線成功以後就可以在ubuntu上進行程式碼除錯了。

下面是上位機的輸出

./client.out: No such file or directory.
(gdb) target remote 192.168.64.203:2001
Remote debugging using 192.168.64.203:2001
Reading /yuyiworkspace/tmp/client.out from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /yuyiworkspace/tmp/client.out from remote target...
Reading symbols from target:/yuyiworkspace/tmp/client.out...done.
Reading /lib/ld-linux.so.3 from remote target...
Reading /lib/ld-linux.so.3 from remote target...
Reading symbols from target:/lib/ld-linux.so.3...done.
0xb6fcea80 in _start () from target:/lib/ld-linux.so.3
(gdb) 

然後可以開始使用了

VSCode+gdbserver圖形化除錯

gdb+gdbserver實現對嵌入式linux程式的除錯,由於主機上的gdb工具是基於命令列的,因此除錯起來不方便,雖然可以加一些外掛,但是依舊和IDE的除錯體驗差很多。如何使用VSCode+gdbserver來實現圖形化介面的嵌入式linux程式除錯。

VSCode設定

給VScode安裝遠端除錯外掛Remote Development點選“除錯新增配置然後選擇C++(GDB/LLDB)選項.

image

image

若沒有配置檔案要點 建立 launch.json檔案

選擇圖中的“ C++(GDB/LLDB)”,會在當前資料夾新建一個名為 launch.json”的檔案,此檔案會存放在 .vscode目錄下,

image

launch.json檔案內容如下所示:

{
    //需要修改的內容: ★ 。
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch", //★配置名稱;顯示在啟動配置下拉選單中。
            "type": "cppdbg", //配置型別。預設
            "request": "launch", //請求配置型別。可以是“啟動”或“附加”。
            //program 程式可執行檔案的完整路徑, ${workspaceFolder}是我當前開啟的檔案工作路徑 家目錄 client.out是我要除錯的程式
            "program": "${workspaceFolder}/zqingyangLib/examples/2024年6月21日_檔案傳輸/temple/client.out", //★
            "args": [], //傳遞給程式的命令列引數
            "stopAtEntry": false, //可選引數。 先打斷點 再執行 如果為 true,則除錯程式應在目標的入口點處停止。如果傳遞了 processId,則不起任何作用。
            "cwd": "${workspaceFolder}/zqingyangLib/examples/2024年6月21日_檔案傳輸/temple", //★需要除錯的應用程式原始碼路徑。main的位置
            "environment": [], //要新增到程式環境的環境變數
            "externalConsole": false, //如果為 true,則為除錯物件啟動控制檯
            "MIMode": "gdb", //要連線到的控制檯除錯程式。允許的值為 "gdb"
            //miDebuggerPath ★此項需要手動新增,用於指定所使用的交叉編譯器 gdb路徑。
            "miDebuggerPath": "/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-gdb",
            "miDebuggerServerAddress": "192.168.64.203:2002" //★此項需要手動新增,遠端 gdbserver伺服器地址。開發板的地址和服務埠
        }
    ]
}

image

VSCode除錯方法

VSCode設定好以後就可以進行除錯了,首先要啟動開發板上的 gdbserver,輸入如下命令

gdbserver 192.168.64.202:2002 client.out

接下來在點選 VSCode上的“除錯” ”->“啟動除錯”按鈕,如圖

image

由於是透過網路進行除錯的,因此啟動除錯以後會有一個建立連線的過程,可能需要幾秒鐘,建立成功以後如上圖

image

image

image

image

依賴環境搭建

LVGL-freeType字型

設定中文字型

LVGL移植使用中文字型檔
FreeType簡介:
FreeType是一款開源的字型渲染引擎,它支援多種字型格式,包括TrueType,Type 1,OpenType依賴關係:LVGL-->FreeType-->Libpng-->zlib
which arm-linux-gcc 可以檢視安裝路徑

第一步:把freetype和zlib中的標頭檔案和庫檔案分別複製到ubuntu的arm-linux-gcc安裝路徑下對應的位置

# 以root賬戶登入Linux
mkdir /root/template
cd /root/template
# 將三個檔案複製到其中
root@yuyi-machine:~/template# ls
freetype_tmp.tar.gz  libfreetype.so.6.18.3  zlib_tmp.tar.gz
# 解壓
tar -xzvf freetype_tmp.tar.gz
tar -xzvf zlib_tmp.tar.gz
# 進入你的交叉編譯器bin資料夾所在的同級位置, 並記錄其位置及目錄
cd /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi

------------
root@yuyi-machine:/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi# ls
arm-linux-gnueabi  bin  gcc-linaro-5.4.1-2017.01-linux-manifest.txt  include  lib  libexec  share
-------------
root@yuyi-machine:/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi# pwd
/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi
-------------
root@yuyi-machine:/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi# cd /root/template #返回前面的解壓位置
root@yuyi-machine:~/template# ls
freetype_tmp  freetype_tmp.tar.gz  libfreetype.so.6.18.3  zlib_tmp  zlib_tmp.tar.gz
--------------


#**************將zlib中的標頭檔案和庫檔案複製到交叉編譯器下對應的位置
root@yuyi-machine:~/template# cd /root/template/zlib_tmp/include
root@yuyi-machine:~/template/zlib_tmp/include# ls
zconf.h  zlib.h
----------------------
root@yuyi-machine:~/template/zlib_tmp/include# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/include/ -rf
--------------------
root@yuyi-machine:~/template/zlib_tmp/lib# cd ~/template/zlib_tmp/lib
root@yuyi-machine:~/template/zlib_tmp/lib# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/lib -rf
---------------------
#**************將freetype中的標頭檔案和庫檔案複製到交叉編譯器下對應的位置
root@yuyi-machine:~/template/freetype_tmp/include# cd /root/template/freetype_tmp/include/freetype2/
-----------------
root@yuyi-machine:~/template/freetype_tmp/include/freetype2# ls
freetype  ft2build.h
-------------------
root@yuyi-machine:~/template/freetype_tmp/include/freetype2# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/include -rf
--------------------
root@yuyi-machine:~/template/freetype_tmp/include/freetype2# cd ~/template/freetype_tmp/lib/
root@yuyi-machine:~/template/freetype_tmp/lib# ls
libfreetype.a  libfreetype.la  libfreetype.so  libfreetype.so.6  libfreetype.so.6.18.3  pkgconfig
root@yuyi-machine:~/template/freetype_tmp/lib# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/lib -rf
--------------------

第二步:將freetypetmp/lib/下的libfreetype.so.6.18.3下載到開發板/usr/lib中. (可從Linux服務端下載)

[root@GEC6818 /yuyiworkspace/LVGL]#cd /usr/lib/
[root@GEC6818 /usr/lib]#ls
libEGL.so                  libnl-idiag-3.so
libGLESv2.so               libnl-idiag-3.so.200
libfreetype.so.6.18.3      libnl-idiag-3.so.200.24.0
libnl-3.la                 libnl-nf-3.la
libnl-3.so                 libnl-nf-3.so
libnl-3.so.200             libnl-nf-3.so.200
libnl-3.so.200.24.0        libnl-nf-3.so.200.24.0
libnl-cli-3.la             libnl-route-3.la
libnl-cli-3.so             libnl-route-3.so
libnl-cli-3.so.200         libnl-route-3.so.200
libnl-cli-3.so.200.24.0    libnl-route-3.so.200.24.0
libnl-genl-3.la            libnl-xfrm-3.la
libnl-genl-3.so            libnl-xfrm-3.so
libnl-genl-3.so.200        libnl-xfrm-3.so.200
libnl-genl-3.so.200.24.0   libnl-xfrm-3.so.200.24.0
libnl-idiag-3.la



第三步: 修改

修改LVGL工程的Makefile檔案

修改
LDFLAGS ?= -lm -lfreetype

修改LVGL工程中lv_conf.h的第671行

//原本是0
/*FreeType library*/
#define LV_USE_FREETYPE 1
#if LV_USE_FREETYPE

#define LV_FREETYPE_SBIT_CACHE 8*1024//原本是0

第四步: 修改LVGL原始碼中/lvgl/examples/libs/freetype/lv_example_freetype_1.c 為下面的內容

#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_FREETYPE

/**
 * Load a font with FreeType
 */
void lv_example_freetype_1(void)
{
    /*Create a font*/
    static lv_ft_info_t info;
    /*FreeType uses C standard file system, so no driver letter is required.*/
    // info.name = "./lvgl/examples/libs/freetype/Lato-Regular.ttf";
    info.name = "/fonts/HYZhengYuan55W.ttf"; // TTF檔案在開發板上的路徑

    info.weight = 24; // 48
    info.style  = FT_FONT_STYLE_NORMAL;
    info.mem    = NULL;
    if(!lv_ft_font_init(&info)) {
        LV_LOG_ERROR("create failed.");
    }

    /*Create style with the new font*/
    static lv_style_t style;
    lv_style_init(&style);
    lv_style_set_text_font(&style, info.font);
    lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);

    /*Create a label with the new style*/
    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_obj_add_style(label, &style, 0);
    lv_label_set_text(label, "革命尚未成功\n同志仍需努力");
    lv_obj_center(label);
}
#else

void lv_example_freetype_1(void)
{
    /*TODO
     *fallback for online examples*/

    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "FreeType is not installed");
    lv_obj_center(label);
}

#endif
#endif

第五步:把字型檔案下載到開發板的/font下面(剛才第四步那個函式寫的字型路徑就是這個) 要先建立/font資料夾

第六步: 開發板設定

因為在上面編譯好的libfreetype.so.6.18.3雖然下載到開發板中的/usr/lib下了,但是因為編譯時,其識別的是不帶後續次版本和修訂號的庫libfreetype.so.6。 所以需要在開發板的/usr/lib下將該庫新增一個軟連結檔案或硬連結檔案皆可。

開發板命令列中
cd  /usr/lib 
ln    libfreetype.so.6.18.3    libfreetype.so.6    -s  
如果已經有軟連結 就不需要再下載了

參考文件

  • Linux下gdb的安裝及使用入門 - 黑澤君 - 部落格園 (cnblogs.com)
  • 正點原子驅動開發手冊 1931頁

相關文章