色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何使用gobpf和uprobe來為Go程序構建函數參數跟蹤程序

Linux閱碼場 ? 來源:Linux內核之旅 ? 作者:Zain Asgar, 陳恒奇 ? 2021-04-03 16:15 ? 次閱讀

這是本系列文章的第一篇,講述了我們如何在生產環境中使用 eBPF 調試應用程序而無需重新編譯/重新部署。這篇文章介紹了如何使用 gobpf 和 uprobe 來為 Go 程序構建函數參數跟蹤程序。這項技術也可以擴展應用于其他編譯型語言,例如 C++,Rust 等。本系列的后續文章將討論如何使用 eBPF 來跟蹤 HTTP/gRPC/SSL 等。

簡介

在調試時,我們通常對了解程序的狀態感興趣。這使我們能夠檢查程序正在做什么,并確定缺陷在代碼中的位置。觀察狀態的一種簡單方法是使用調試器來捕獲函數的參數。對于 Go 程序來說,我們經常使用 Delve 或者 GDB。

在開發環境中,Delve 和 GDB 工作得很好,但是在生產環境中并不經常使用它們。那些使調試器強大的特性也讓它們不適合在生產環境中使用。調試器會導致程序中斷,甚至允許修改狀態,這可能會導致軟件產生意外故障。

為了更好地捕獲函數參數,我們將探索使用 eBPF(在 Linux 4.x+ 中可用)以及高級的 Go 程序庫 gobpf。

eBPF 是什么?

擴展的 BPF(eBPF) 是 Linux 4.x+ 里的一項內核技術。你可以把它想像成一個運行在 Linux 內核中的輕量級的沙箱虛擬機,可以提供對內核內存的經過驗證的訪問。

如下概述所示,eBPF 允許內核運行 BPF 字節碼。盡管使用的前端語言可能會有所不同,但它通常是 C 的受限子集。一般情況下,使用 Clang 將 C 代碼編譯為 BPF 字節碼,然后驗證這些字節碼,確保可以安全運行。這些嚴格的驗證確保了機器碼不會有意或無意地破壞 Linux 內核,并且 BPF 探針每次被觸發時,都只會執行有限的指令。這些保證使 eBPF 可以用于性能關鍵的工作負載,例如數據包過濾,網絡監控等。

從功能上講,eBPF 允許你在某些事件(例如定時器,網絡事件或函數調用)觸發時運行受限的 C 代碼。當在函數調用上觸發時,我們稱這些函數為探針,它們既可以用于內核里的函數調用(kprobe) 也可以用于用戶態程序中的函數調用(uprobe)。本文重點介紹使用 uprobe 來動態跟蹤函數參數。

Uprobe

uprobe 可以通過插入觸發軟中斷的調試陷阱指令(x86 上的 int3)來攔截用戶態程序。這也是調試器的工作方式。uprobe 的流程與任何其他 BPF 程序基本相同,如下圖所示。經過編譯和驗證的 BPF 程序將作為 uprobe 的一部分執行,并且可以將結果寫入緩沖區。

fe942248-8cdd-11eb-8b86-12bb97331649.jpg

讓我們看看 uprobe 是如何工作的。要部署 uprobe 并捕獲函數參數,我們將使用這個簡單的示例程序。這個 Go 程序的相關部分如下所示。

main() 是一個簡單的 HTTP 服務器,在路徑 /e 上公開單個 GET 端點,該端點使用迭代逼近來計算歐拉數(e)。computeE接受單個查詢參數(iterations),該參數指定計算近似值要運行的迭代次數。迭代次數越多,近似值越準確,但會消耗指令周期。理解函數背后的數學并不是必需的。我們只是想跟蹤對 computeE 的任何調用的參數。

// computeE computes the approximation of e by running a fixed number of iterations.

func computeE(iterations int64) float64 {

res := 2.0

fact := 1.0

for i := int64(2); i 《 iterations; i++ {

fact *= float64(i)

res += 1 / fact

}

return res

}

func main() {

http.HandleFunc(“/e”, func(w http.ResponseWriter, r *http.Request) {

// Parse iters argument from get request, use default if not available.

// 。.. removed for brevity 。..

w.Write([]byte(fmt.Sprintf(“e = %0.4f

”, computeE(iters))))

})

// Start server.。.

}

要了解 uprobe 的工作原理,讓我們看一下二進制文件中如何跟蹤符號。由于 uprobe 通過插入調試陷阱指令來工作,因此我們需要獲取函數所在的地址。Linux 上的 Go 二進制文件使用 ELF 存儲調試信息。除非刪除了調試數據,否則即使在優化過的二進制文件中也可以找到這些信息。我們可以使用 objdump 命令檢查二進制文件中的符號:

[0] % objdump --syms app|grep computeE

00000000006609a0 g F .text 000000000000004b main.computeE

從這個輸出中,我們知道函數 computeE 位于地址 0x6609a0。要看到它前后的指令,我們可以使用 objdump 來反匯編二進制文件(通過添加 -d 選項實現)。反匯編后的代碼如下:

[0] % objdump -d app | less

00000000006609a0 《main.computeE》:

6609a0: 48 8b 44 24 08 mov 0x8(%rsp),%rax

6609a5: b9 02 00 00 00 mov $0x2,%ecx

6609aa: f2 0f 10 05 16 a6 0f movsd 0xfa616(%rip),%xmm0

6609b1: 00

6609b2: f2 0f 10 0d 36 a6 0f movsd 0xfa636(%rip),%xmm1

由此可見,當 computeE 被調用時會發生什么。第一條指令是 mov 0x8(%rsp), %rax。它把 rsp 寄存器偏移 0x8 的內容移動到 rax 寄存器。這實際上就是上面的輸入參數 iterations。Go 的參數在棧上傳遞。

有了這些信息,我們現在就可以繼續深入,編寫代碼來跟蹤 computeE 的參數了。

構建跟蹤程序

要捕獲事件,我們需要注冊一個 uprobe 函數,還需要一個可以讀取輸出的用戶空間函數。如下圖所示。我們將編寫一個稱為跟蹤程序的二進制文件,它負責注冊 BPF 代碼并讀取 BPF 代碼的結果。如圖所示,uprobe 簡單地寫入 perf buffer,這是用于 perf 事件的 Linux 內核數據結構。

fec975f6-8cdd-11eb-8b86-12bb97331649.png

現在,我們已了解了涉及到的各個部分,下面讓我們詳細研究添加 uprobe 時發生的情況。下圖顯示了 Linux 內核如何使用uprobe 修改二進制文件。軟中斷指令(int3)作為第一條指令被插入 main.computeE 中。這將導致軟中斷,從而允許 Linux 內核執行我們的 BPF 函數。然后我們將參數寫入 perf buffer,該緩沖區由跟蹤程序異步讀取。

ff0bbdbc-8cdd-11eb-8b86-12bb97331649.png

BPF 函數相對簡單,C代碼如下所示。我們注冊這個函數,每次調用 main.computeE 時都將調用它。一旦調用,我們只需讀取函數參數并寫入 perf buffer。設置緩沖區需要很多樣板代碼,可以在完整的示例中找到。

#include 《uapi/linux/ptrace.h》

BPF_PERF_OUTPUT(trace);

inline int computeECalled(struct pt_regs *ctx) {

// The input argument is stored in ax.

long val = ctx-》ax;

trace.perf_submit(ctx, &val, sizeof(val));

return 0;

}

現在我們有了一個用于 main.computeE 函數的功能完善的端到端的參數跟蹤程序!下面的視頻片段展示了這一結果。

ff4b47e8-8cdd-11eb-8b86-12bb97331649.gif

另一個很棒的事情是,我們可以使用 GDB 來查看對二進制文件所做的修改。在運行我們的跟蹤程序之前,我們輸出地址 0x6609a0 的指令。

(gdb) display /4i 0x6609a0

10: x/4i 0x6609a0

0x6609a0 《main.computeE》: mov 0x8(%rsp),%rax

0x6609a5 《main.computeE+5》: mov $0x2,%ecx

0x6609aa 《main.computeE+10》: movsd 0xfa616(%rip),%xmm0

0x6609b2 《main.computeE+18》: movsd 0xfa636(%rip),%xmm1

而這是在我們運行跟蹤程序之后。我們可以清楚地看到,第一個指令現在變成 int3 了。

(gdb) display /4i 0x6609a0

7: x/4i 0x6609a0

0x6609a0 《main.computeE》: int3

0x6609a1 《main.computeE+1》: mov 0x8(%rsp),%eax

0x6609a5 《main.computeE+5》: mov $0x2,%ecx

0x6609aa 《main.computeE+10》: movsd 0xfa616(%rip),%xmm0

盡管我們為該特定示例對跟蹤程序進行了硬編碼,但是這個過程是可以通用化的。Go 的許多方面(例如嵌套指針,接口,通道等)讓這個過程變得有挑戰性,但是解決這些問題可以使用現有系統中不存在的另一種檢測模式。另外,因為這一過程工作在二進制層面,它也可以用于其他語言(C++,Rust 等)編譯的二進制文件。我們只需考慮它們各自 ABI 的差異。

下一步是什么?

使用 uprobe 進行 BPF 跟蹤有其自身的優缺點。當我們需要觀察二進制程序的狀態時,BPF 很有用,甚至在連接調試器會產生問題或者壞處的環境(例如生產環境二進制程序)。最大的缺點是,即使是最簡單的程序狀態的觀測性,也需要編寫代碼來實現。編寫和維護 BPF 代碼很復雜。沒有大量高級工具,不太可能把它當作一般的調試手段。
編輯:lyn

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • LINUX內核
    +關注

    關注

    1

    文章

    316

    瀏覽量

    21664
  • 函數參數
    +關注

    關注

    0

    文章

    6

    瀏覽量

    5998
  • BPF
    BPF
    +關注

    關注

    0

    文章

    25

    瀏覽量

    4012

原文標題:在生產環境中使用 eBPF 調試 GO 程序

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Todoist一鍵時間跟蹤

    過三個簡單的步驟將您的Todoist工作區連接到TMetric時間跟蹤應用。通過單擊鼠標跟蹤執行任務所花費的時間。項目獲取廣泛而精確的報告。 添加計時器按鈕到Todoist任務中 完成這三個簡單
    的頭像 發表于 01-03 11:08 ?69次閱讀
    Todoist一鍵時間<b class='flag-5'>跟蹤</b>

    嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-spi編程示例之spi編寫程序

    傳輸數據。它使用`ioctl`系統調用和`SPI_IOC_MESSAGE`命令執行SPI數據傳輸。第四部分:`main`函數程序的入口點。它將`send_num`變量設置38,然
    發表于 11-07 09:36

    飛凌嵌入式ElfBoard ELF 1板卡-spi編程示例之spi編寫程序

    傳輸數據。它使用`ioctl`系統調用和`SPI_IOC_MESSAGE`命令執行SPI數據傳輸。第四部分:`main`函數程序的入口點。它將`send_num`變量設置38,然
    發表于 11-06 09:15

    面試常考+1:函數指針與指針函數、數組指針與指針數組

    函數是指返回值指針的函數。語法:返回值類型*函數名(參數列表)。示例代碼:#include#includeint*getNumber(in
    的頭像 發表于 08-10 08:11 ?909次閱讀
    面試常考+1:<b class='flag-5'>函數</b>指針與指針<b class='flag-5'>函數</b>、數組指針與指針數組

    如何看懂檢測設備程序邏輯

    的地方,通常是主函數(main function)或啟動函數(startup function)。在程序入口處,通常會進行一些初始化操作,如初始化全局變量、配置硬件設備等。 程序主體
    的頭像 發表于 07-17 16:50 ?446次閱讀

    python函數的萬能參數

    我們通過一個簡單的事例展示一下函數的萬能參數,我們先寫一個最簡單的函數
    的頭像 發表于 07-17 14:56 ?354次閱讀
    python<b class='flag-5'>函數</b>的萬能<b class='flag-5'>參數</b>

    STM32F103VE ADC采樣正弦波,程序阻塞如何處理?

    函數的實現是匯編實現的,無法跟蹤。請問應該如何處理? 如果有類似的例子,也請給我參考一下。 請指教,謝謝! 程序代碼: u32 adcin[1024]={0}; while(1) { for(i=0
    發表于 05-15 07:23

    使用Redis和Spring?Ai構建rag應用程序

    隨著AI技術的不斷進步,開發者面臨著如何有效利用現有工具和技術加速開發過程的挑戰。Redis與SpringAI的結合為Java開發者提供了一個強大的平臺,以便快速構建并部署響應式AI應用。探索這一
    的頭像 發表于 04-29 08:04 ?1059次閱讀
    使用Redis和Spring?Ai<b class='flag-5'>構建</b>rag應用<b class='flag-5'>程序</b>

    Go語言中的函數、方法與接口詳解

    Go 沒有類,不過可以為結構體類型定義方法。方法就是一類帶特殊的接收者參數函數。方法接收者在它自己的參數列表內,位于 func 關鍵字和方法名之間。(非結構體類型也可以定義方法)
    的頭像 發表于 04-23 16:21 ?854次閱讀

    使用Docker部署Go Web應用程序步驟

    大多數情況下Go應用程序被編譯成單個二進制文件,web應用程序則會包括模版和配置文件。而當一個項目中有很多文件的時候,由于很多文件沒有同步就會導致錯誤的發生并且產生很多的問題。
    發表于 04-20 09:33 ?522次閱讀
    使用Docker部署<b class='flag-5'>Go</b> Web應用<b class='flag-5'>程序</b>步驟

    學習筆記|如何用Go程序采集溫濕度傳感器數據

    在共創社內部的交流中,先前有一位成員展示了如何借助C語言實現對AHT20溫濕度傳感器數據的讀取。這一實例觸發了另一位共創官的靈感,他決定采納Go語言重新構建這一數據采集流程。接下來,我們將詳細解析
    的頭像 發表于 03-21 11:46 ?735次閱讀
    學習筆記|如何用<b class='flag-5'>Go</b><b class='flag-5'>程序</b>采集溫濕度傳感器數據

    什么是pipeline?Go構建流數據pipeline的技術

    本文介紹了在 Go構建流數據pipeline的技術。 處理此類pipeline中的故障很棘手,因為pipeline中的每個階段可能會阻止嘗試向下游發送值,并且下游階段可能不再關心傳入的數據。
    的頭像 發表于 03-11 10:16 ?624次閱讀

    如何使用exit()、_exit()和_Exit()終止程序運行呢?

    在Linux系統下,你可以使用 exit()、_exit() 和 _Exit() 終止程序運行,特別是在出現錯誤或執行失敗的情況下。
    的頭像 發表于 02-22 12:20 ?954次閱讀

    如何使用linux下gdb調試python程序

    如何使用linux下gdb調試python程序? 在Linux下,可以使用GDB(GNU調試器)調試Python程序。GDB是一個強大的調試工具,可以幫助開發者診斷和修復
    的頭像 發表于 01-31 10:41 ?2653次閱讀

    GD32 MCU是如何進入中斷函數

    用過GD32 MCU的小伙伴們都知道,程序是順序執行的,但當有中斷的時候程序會跳轉到中斷函數,執行完中斷函數
    的頭像 發表于 01-30 09:45 ?1112次閱讀
    GD32 MCU是如何進入中斷<b class='flag-5'>函數</b>的
    主站蜘蛛池模板: 好色美女小雅| 日韩美一区二区| 露露的性战k8经典| 欧美猛男gaygayxxgv| 无码专区无码专区视频网网址| 亚洲精品天堂无码中文字幕影院| 中文文字幕文字幕亚洲色| 草神被爆漫画羞羞漫画| 好男人午夜www视频在线观看 | 看看妇女的B免费看| 免费看国产精品麻豆| 日本最新免费区中文| 亚洲视频无码高清在线| 被窝伦理电影午夜| 极品虎白在线观看| 青柠在线观看视频在线| 亚洲精品久久久无码| china野外18:19| 狠狠人妻久久久久久综合九色| 彭丹吃奶门| 一边吃奶一边添P好爽故事| 成人AV精品视频| 久久亚洲精品AV成人无| 我不卡影院手机在线观看| 9277高清在线观看视频| 国产在线精品亚洲第1页| 欧美亚洲日韩欧洲不卡| 一级特黄视频| 国产精品嫩草影院| 男女作爱在线播放免费网页版观看| 亚洲成人黄色在线| 阿片在线播放| 久久视频精品3线视频在线观看| 无人区尖叫之夜美女姐姐视频| 99精品久久| 精子网久久国产精品| 空姐厕所啪啪啪| 世界第一黄暴漫画家| 99re热视频这里只有精品| 狠狠干狠狠色| 天天操天天干天天爽|