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

来源:https://www.cnblogs.com/zqingyang/p/18279323
-Advertisement-
Play Games

本文介紹瞭如何使用GDB調試工具、如何將GDB移植到linu開發板上、如何在交叉編譯時使用GDB,,如何設置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環境準備就緒, 會有歡迎界面, 按一下回車鍵, 開始進入命令輸入

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”命令,或者按下回車鍵, gdb調試工具中回車鍵表示重覆上一個命令!

回車鍵

重覆上一個命令

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  
如果已經有軟鏈接 就不需要再下載了

參考文檔

本文來自博客園,作者:舟清颺,轉載請註明原文鏈接:https://www.cnblogs.com/zqingyang/p/18279323


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文詳細介紹瞭如何在 CentOS 伺服器上通過 Docker 安裝和配置迅雷NAS,實現高效的遠程下載功能,並提供了詳細的命令和配置步驟。 ...
  • 第九章 列印輸出實驗 1)實驗平臺:正點原子DNK210開發板 2)章節摘自【正點原子】DNK210使用指南 - CanMV版 V1.0 3)購買鏈接:https://detail.tmall.com/item.htm?&id=782801398750 4)全套實驗源碼+手冊+視頻下載地址:http ...
  • 作者:小牛呼嚕嚕 大家好,我是呼嚕嚕,由於x86保護模式是比較複雜晦澀的,所以特地單拉出來,實模式和保護模式一個重要的更新就是對記憶體的管理與保護,並且隨著軟體的發展,為了極致地壓榨CPU的性能,硬體和軟體都做出了許多努力,為了更好的管理記憶體,引入分段,分頁,段頁等等。本文會沿著記憶體的主線,穿插於實模 ...
  • 第八章 CanMV IDE初體驗 1)實驗平臺:正點原子DNK210開發板 2) 章節摘自【正點原子】DNK210使用指南 - CanMV版 V1.0 3)購買鏈接:https://detail.tmall.com/item.htm?&id=782801398750 4)全套實驗源碼+手冊+視頻下載 ...
  • 最近有個項目需要遠距離讀uart 串口列印出來的數據, 但是淘寶的調試助手太貴了, 開源平臺找了圈也許是因為功能太簡單, 好像沒怎麼找到或者說連接配置的方式很麻煩, 所以我花了半天時間寫了一個.如果有同樣需求的小白可以直接用這個程式跑 本方案主要是 把esp32配置成AP模式. 並且通過TCP/UD ...
  • vim的三種模式 一般模式 以vim打開一個文件就直接進入一般模式了。在這個模式中,你可以使用h,j,k,l按鍵移動游標,也可以使用刪除字元或刪除整行來處理文件內容,也可以使用複製粘貼處理文件內容。 編輯模式 在一般模式中按下A,a,I,i,O,o,R,r任何一個按鍵,就可以進入編輯模式,在界面左下 ...
  • 導航 0 前言 1 許可權匹配流程 2 五種身份變化 3 有效用戶/組 4 特權對 Shell 腳本無效 5 Sudo 與 SUID/SGID 的優先順序 6 SUID、SGID、Sticky 各自的功能 0、前言 Linux最優秀的地方之一,就在於他的多人多工環境。而為了讓各個使用者具有較保密的檔案資 ...
  • IP重組 ip重組這部分 4.19內核與3.10內核有些差別,4.9.134以後內核中不使用低水位和工作隊列了,同時使用了rhashtable 替代了 hash bucket的概念,在3.10內核中使用1024個hash bucket, 每個bucket中最多存放128個分片隊列,在4.19內核中所 ...
一周排行
    -Advertisement-
    Play Games
  • 通過WPF的按鈕、文本輸入框實現了一個簡單的SpinBox數字輸入用戶組件並可以通過數據綁定數值和步長。本文中介紹了通過Xaml代碼實現自定義組件的佈局,依賴屬性的定義和使用等知識點。 ...
  • 以前,我看到一個朋友在對一個系統做初始化的時候,通過一組魔幻般的按鍵,調出來一個隱藏的系統設置界面,這個界面在常規的菜單或者工具欄是看不到的,因為它是一個後臺設置的關鍵界面,不公開,同時避免常規用戶的誤操作,它是作為一個超級管理員的入口功能,這個是很不錯的思路。其實Winform做這樣的處理也是很容... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他的程式每次關閉時就會自動崩潰,一直找不到原因讓我幫忙看一下怎麼回事,這位朋友應該是第二次找我了,分析了下 dump 還是挺經典的,拿出來給大家分享一下吧。 二:WinDbg 分析 1. 為什麼會崩潰 找崩潰原因比較簡單,用 !analyze -v 命 ...
  • 在一些報表模塊中,需要我們根據用戶操作的名稱,來動態根據人員姓名,更新報表的簽名圖片,也就是電子手寫簽名效果,本篇隨筆介紹一下使用FastReport報表動態更新人員簽名圖片。 ...
  • 最新內容優先發佈於個人博客:小虎技術分享站,隨後逐步搬運到博客園。 創作不易,如果覺得有用請在Github上為博主點亮一顆小星星吧! 博主開始學習編程於11年前,年少時還只會使用cin 和cout ,給單片機點點燈。那時候,類似async/await 和future/promise 模型的認知還不是 ...
  • 之前在阿裡雲ECS 99元/年的活動實例上搭建了一個測試用的MINIO服務,以前都是直接當基礎設施來使用的,這次準備自己學一下S3相容API相關的對象存儲開發,因此有了這個小工具。目前僅包含上傳功能,後續計劃開發一個類似圖床的對象存儲應用。 ...
  • 目錄簡介快速入門安裝 NuGet 包實體類User資料庫類DbFactory增刪改查InsertSelectUpdateDelete總結 簡介 NPoco 是 PetaPoco 的一個分支,具有一些額外的功能,截至現在 github 星數 839。NPoco 中文資料沒多少,我是被博客園群友推薦的, ...
  • 前言 前面使用 Admin.Core 的代碼生成器生成了通用代碼生成器的基礎模塊 分組,模板,項目,項目模型,項目欄位的基礎功能,本篇繼續完善,實現最核心的模板生成功能,並提供生成預覽及代碼文件壓縮下載 準備 首先清楚幾個模塊的關係,如何使用,簡單畫一個流程圖 前面完成了基礎的模板組,模板管理,項目 ...
  • 假設需要實現一個圖標和文本結合的按鈕 ,普通做法是 直接重寫該按鈕的模板; 如果想作為通用的呢? 兩種做法: 附加屬性 自定義控制項 推薦使用附加屬性的形式 第一種:附加屬性 創建Button的附加屬性 ButtonExtensions 1 public static class ButtonExte ...
  • 在C#中,委托是一種引用類型的數據類型,允許我們封裝方法的引用。通過使用委托,我們可以將方法作為參數傳遞給其他方法,或者將多個方法組合在一起,從而實現更靈活的編程模式。委托類似於函數指針,但提供了類型安全和垃圾回收等現代語言特性。 基本概念 定義委托 定義委托需要指定它所代表的方法的原型,包括返回類 ...