在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

如何調試glibc?

Linux閱碼場 ? 來源:礎光操作系統 ? 2023-05-11 09:03 ? 次閱讀

背景

國科礎石操作系統團隊在開發礎光智能操作系統的過程中,需要分析glibc啟動過程中的異常信息,在此過程中探索出一條快速調試glibc流程的方法。

由于glibc啟動代碼復雜,printf、ptrace等輔助調試手段還不能正常使用,給分析過程帶來困難。本文探索的方法避免了對printf、ptrace的依賴。

glibc 簡介

glibc是Linux系統中常用的C運行時庫,它是GNU項目的一部分,是一組函數和子例程的集合,為Linux操作系統上的C程序提供了基本的運行時支持。

glibc提供了Linux系統所需的底層功能和工具,包括內存管理、線程支持、網絡編程、文件系統訪問、數學計算、時間和日期處理、本地化支持等等。它還提供了標準的C庫函數,如字符串操作、輸入輸出、數據結構操作等等。

glibc還提供了一些高級功能,例如動態內存管理、線程安全、多語言支持、安全性等等。它提供了一些重要的頭文件和宏定義,例如stdio.h、stdlib.h、string.h、time.h等等。

glibc還提供了一些調試和性能分析工具,例如gdb調試器和strace系統調用跟蹤器等。

總之,glibc是Linux系統中最重要的C運行時庫之一,提供了許多基本和高級功能,為開發人員提供了強大的工具和支持,使得他們能夠更加輕松地編寫高質量、高效、可靠的C程序。

glibc是什么?

舉個簡單的例子來解釋glibc大概做了什么 :

#include 


int sum (int a, int b) {
    return a + b;
}


int main (void) {
    int a = 35;
    int b = 24;
    printf("%d + %d = %d
", a, b, sum(a, b));
    return 0;
}

當我們編寫一個c程序時,在 glibc 的幫助下會給我們一種錯覺 : 當我們運行編譯出來的二進制文件,操作系統直接運行到 main 函數,然后執行由提供的函數或我們自己編寫的邏輯代碼,在上述例子中,我們使用了libc提供的 "printf" 打印函數。我們自己編寫了一個求和的邏輯代碼。那么glibc真的就是提供一些函數接口的庫么?

其實對于操作系統而言,它會都不"認識"main函數。而一個進程的執行也并非由 main 函數開始的。在鏈接時,鏈接器會設置函數入口,而該可執行程序入口不是 main。

[vizdl@localhost glibc_debug]# readelf -h build/crt.elf  
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x400580
  Start of program headers:          64 (bytes into file)
  Start of section headers:          634584 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         6
  Size of section headers:           64 (bytes)
  Number of section headers:         28
  Section header string table index: 27

在這里我將上述代碼編譯鏈接后,使用 readelf -h 讀取該可執行文件的頭部信息,可以看到 "Entry point address: 0x400580",表明可執行程序的入口地址是 0x400580。

[vizdl@localhost glibc_debug]# readelf -s  build/crt.elf  | grep 400580
    29: 0000000000400580     0 NOTYPE  LOCAL  DEFAULT    6 $x
  2471: 0000000000400580    60 FUNC    GLOBAL HIDDEN     6 _start

我們通過 readelf -s 指令查看該二進制的符號表,可以看到, elf 執行的第一個"函數"是 _start,而不是 main。可執行文件執行到main函數之前,其實 glibc 偷偷加了一些代碼。這部分代碼籠統地講其實就是做了一些進程環境設置的工作,讓編寫c代碼的程序員可以避免每次都要編寫重復的進程的環境設置!glibc真切地做到了做好事不留名:)但是今天我們提供一種方式,讓大家都能看到glibc做的好事~

glibc 開發者如何調試 glibc?

在 glibc 中,一些地方調用c庫函數會出現問題,特別是 _start -> main 這段代碼,由于進程環境未初始化,導致大多數的 glibc 的函數運行的前提無法保證,于是絕大多數 glibc 的函數無法在這段代碼內運行,這導致對glibc的觀察可謂是困難重重,如何提供一種簡單通用且可靠的調試方法一直是業界的難題。

我們在 glibc 入口函數找到了一些代碼,并調用自定義函數dl_debug_printf來進行調試輸出:

LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
         int argc, char **argv,
#ifdef LIBC_START_MAIN_AUXVEC_ARG
         ElfW(auxv_t) *auxvec,
#endif
         __typeof (main) init,
         void (*fini) (void),
         void (*rtld_fini) (void), void *stack_end)
{
    ...
    if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
        GLRO(dl_debug_printf) ("
initialize program: %s

", argv[0]);
    ...
}

但是 dl_debug_printf 應該怎么用?它依賴什么?有什么限制?要深入分析會很麻煩,而且在使用中很大概率會因為不夠了解其原理而導致遇到各種坑。我們何不另辟蹊徑,自己制造出一種可靠的調試方式?

上述問題都能得以解決!

另辟蹊徑

在 glibc 中添加一個調試函數 dbg_printf, 該調試函數依賴我們"新增"的系統調用,并且該系統調用僅僅通過 printk 打印的方式將傳入的參數打印到 printk 環形緩沖區中。再通過 dmesg 來取數據。

如果真正地新增系統調用,則會導致需要重新編譯內核,不夠通用。我們采用了 tracepoint hook 點,依賴寄存器讀取修改的方式,支持以驅動的方法實現一個系統調用。

本方法的要點在于:

(1) 新添加的dbg_printf不依賴于標準C庫的任何系統調用,實現了一份完全干凈的字符串格式化方法。

(2) 實現一個內核模塊,在內核模塊中 實現一個tracepoint hook,該 tracepoint hook會監控sys_enter事件,這樣就可以攔截系統調用,而不必通過修改Linux源代碼的方式,來擴展新的系統調用。

我們做了什么

該項目一共包含三個主體 : glibc, debug_printf 驅動, 一個簡單的測試程序 test.c。

glibc

我們對glibc添加了一個補丁,該補丁在 make devel 時打到 glibc 源碼中。

這個補丁添加了 dbg_printf 調試函數的實現

int
__dbg_printf (const char *fmt, ...)
{
    int ret = 0;
    int len = 0;
    char buf[buffsize];
    va_list ap;


    memset(buf, 0, buffsize);
    va_start(ap, fmt);
    len = dbg_vsnprintf(buf, buffsize, fmt, ap);
    buf[len] = 0;
    va_end(ap);
    ret = syscall_intface2(__NR_dbg, (long)buf, len + 1);


    return ret;
}


#undef _IO_printf
ldbl_strong_alias (__dbg_printf, dbg_printf)
ldbl_strong_alias (__dbg_printf, _IO_dbg_printf)

這個補丁調用 dbg_printf 調試函數,打印該進程收到的參數。

void print_args (int argc, char **argv) {
  int i;
  dbg_printf("argc : %d
", argc);
  for (i = 0; i < argc; i++) {
    dbg_printf("argv[%d] : %s
", i, argv[i]);
  }
}


LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
         int argc, char **argv,
#ifdef LIBC_START_MAIN_AUXVEC_ARG
         ElfW(auxv_t) *auxvec,
#endif
         __typeof (main) init,
         void (*fini) (void),
         void (*rtld_fini) (void), void *stack_end)
{
  ...
  /* Perform IREL{,A} relocations.  */
  ARCH_SETUP_IREL ();


  /* print argc and argv */
  print_args(argc, argv);


  /* The stack guard goes into the TCB, so initialize it early.  */
  ARCH_SETUP_TLS ();
  ...
}

debug_printf 驅動

利用 tracepoint sys_enter hook 點,偽造一個不存在的系統調用。

test.c

一個普通的c程序,該程序會被鏈接到我們編譯的glibc上,因此我們在 glibc 上的改動(打印參數),會在運行該程序時執行。

#include 


int main (void) {
    printf("Hello, glibcdbg
");
    return 0;
}

遇到的問題

我們在 glibc 中使用 dbg_printf 時調用 vsnprintf 與 syscall 函數時,居然出現了堆棧錯誤,后續將其換成了自己實現的 dbg_vsnprintf 和 syscall_intface2。

實驗環境

glibc的編譯與鏈接存在著許多坑,為避免讀者再次趟坑,我們提供了docker編譯環境,避免環境問題導致實驗失敗。

推薦實驗環境

推薦使用 ubuntu 18.04 x86_64 架構環境。

vizdl@ubuntu:~/glibcdbg$ uname -a
Linux ubuntu 5.4.0-146-generic #163~18.04.1-Ubuntu SMP Mon Mar 20 1559 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

準備環境依賴

該項目需要依賴基本的編譯工具

sudo apt install gcc make git -y

該項目依賴docker,所以第一步需要先安裝docker(docker需要內核版本較高,最低內核版本 linux 3.10),如若已安裝可跳過。

sudo curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

拉取項目

gitclonegit@gitee.com:kernelsoft/glibcdbg.git

構建編譯環境 : 這步驟主要是下載glibc代碼,打上我們的補丁以及構建 docker image。

make devel

編譯 : 這步驟主要是編譯驅動模塊/測試小程序/glibc

make build

安裝驅動 : 該步驟僅安裝驅動模塊

make install

運行測試案例并輸出 : 運行測試小程序然后使用 dmesg 獲取我們使用 printk 輸出在內核的信息

make run

卸載驅動 : 該步驟僅卸載驅動模塊

make uninstall

清理環境 : 恢復到初始項目狀態。

make distclean





審核編輯:劉清

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

    關注

    4

    文章

    595

    瀏覽量

    27449
  • 調試器
    +關注

    關注

    1

    文章

    305

    瀏覽量

    23782
  • GNU
    GNU
    +關注

    關注

    0

    文章

    143

    瀏覽量

    17517
  • GDB調試
    +關注

    關注

    0

    文章

    24

    瀏覽量

    1469

原文標題:硬核:如何調試glibc

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

收藏 人收藏

    評論

    相關推薦

    交叉編譯glibc時候出錯,尋求幫助

    各位好:自己在建立arm交叉編譯工具鏈的過程中,交叉編譯glibc的時候出現了如下錯誤:/opt/gcc-arm/lib/gcc/arm-linux-gnueabi/4.6.4
    發表于 07-18 12:09

    影響 Linux 系統安全基石的 glibc 嚴重漏洞

    編者按:這個消息是幾個月前曝出的,也許我們該對基礎軟件的安全問題更加重視。谷歌披露的一個嚴重漏洞影響到了主流的 Linux 發行版。glibc 的漏洞可能導致遠程代碼執行。幾個月前,Linux 用戶
    發表于 06-25 10:01

    導入tensorflow時未找到“GLIBC_2.23”錯誤

    導入tensorflow時,它給我一個錯誤。附上錯誤的屏幕截圖。請幫忙。GLIBC_Error.PNG 40.9 K.以上來自于谷歌翻譯以下為原文Hi, I created a new conda
    發表于 11-14 09:59

    libc、glibc和glib有什么關系

    libc、glibc和glib的關系
    發表于 04-14 11:44

    【源碼】arm-linux-gcc-3.4.5-glibc-2.3.6.tar

    arm-linux-gcc-3.4.5-glibc-2.3.6.tar程序源碼回復帖子查看資料下載鏈接:[hide][/hide]
    發表于 08-18 10:33

    0K335XD的GLIBC建議升級一下

    0K335XD的GLIBC2.12.2的,但QT5要求的版本較高,建議官方升級一下
    發表于 01-12 06:13

    Yocto Bitbake Glibc構建失敗了怎么解決?

    我正在嘗試構建 Yocto 映像,但在編譯 glibc 時構建失敗。我運行了這個命令:bitbake 精簡版圖像我收到如下編譯錯誤: | /media/ubu/LocalDisk
    發表于 03-24 08:01

    全志Tina Linux下如何編譯glibc

    / make工具 注意由于AW服務器make版本為3.8.1,在編譯glibc高版本時候不兼容,所以需要更新make工具。假如服務器make版本較高,可以不用更新make工具。 網址 http
    發表于 06-02 10:00

    使用全志方案遇到glibc庫版本低以及編譯報錯的解決方法

    Glibc 包含了linux一些主要的C庫,用于分配內存、搜索目錄、打開關閉文件、讀寫文件、字串處理、模式匹配、數學計算等,在遇到glibc庫版本低編譯還報錯的情況時,遵循以下
    發表于 06-25 09:48

    在soc平臺按照bmnnsdk2開發手冊設置環境后出現glibc版本問題如何解決?

    python報出下列錯誤: vi: /system/usr/lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29\' not found
    發表于 09-18 06:29

    glibc內存管理存在的共性問題及解決方法

    引言 對于嵌入式設備來說,用戶態內存管理是一項基礎功能,目前主流的用戶態內存管理庫有glibc、uclibc、tcmalloc、jemalloc等。 本文基于glibc2.17版本進行分析,圍繞
    的頭像 發表于 06-18 14:50 ?3319次閱讀

    Glibc內存管理之Ptmalloc2源代碼分析

    Glibc內存管理之Ptmalloc2源代碼分析
    發表于 07-29 09:20 ?24次下載

    glibc導致的堆外內存泄露的排查過程

    本文記錄一次glibc導致的堆外內存泄露的排查過程。
    的頭像 發表于 09-01 09:43 ?736次閱讀
    <b class='flag-5'>glibc</b>導致的堆外內存泄露的排查過程

    如何使用tcmalloc來替換glibc的malloc

    代碼中使用tcmalloc替換malloc 我們如何使用tcmalloc來替換glibc的malloc呢? 在鏈接tcmalloc的時候我們可以使用以下任意一種方式: 1.啟動程序之前,預先加載
    的頭像 發表于 11-11 16:52 ?2272次閱讀
    如何使用tcmalloc來替換<b class='flag-5'>glibc</b>的malloc

    glibc的內存分配回收策略

    。malloc、free均發生在這個區域。本文將簡單介紹下glibc在動態內存管理方面的機制,拋磚引玉,希望能和大家
    的頭像 發表于 11-13 11:16 ?705次閱讀
    <b class='flag-5'>glibc</b>的內存分配回收策略
    主站蜘蛛池模板: 精品爱爱| 6969精品视频在线观看| 天天色爱| 特级生活片| 日本免费的一级绿象| 你懂的在线观看网址| 狠狠狠| 操你啦网站| 天天干天天爱天天射| 久久黄视频| 黄色h网站| 高h污快穿文汁水四溅| 亚洲mv在线观看| 人人爽天天碰天天躁夜夜躁| 久久h| 一本大道加勒比久久综合| 欧美大片国产在线永久播放| 高清视频黄色录像免费| 性夜影院爽黄a爽免费视| 一品毛片| 欧美三级在线观看视频| 福利视频欧美| 日韩一级片免费| 人人做人人爽人人爱秋霞影视| 免费看黄的视频网站| 特级全黄大片| 九色综合久久综合欧美97| 亚洲午夜精品一区二区| 国产精品影视| 久久婷婷综合中文字幕| 国产在线视频不卡| 天天草天天射| 男人操女人免费网站| 在线免费色| 免费两性的视频网站| 欧美性一区二区三区| 国产精品99r8在线观看| 国产成人精品三级| 日本特级黄色录像| 亚洲日本在线观看| 四虎影视大全免费入口|