亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現(xiàn)在的位置是:首頁 > 技術(shù)閱讀 >  Linux中對【庫函數(shù)】的調(diào)用進行跟蹤的 3 種【插樁】技巧

Linux中對【庫函數(shù)】的調(diào)用進行跟蹤的 3 種【插樁】技巧

時間:2024-02-10

目錄

  • 什么是插樁?

  • 插樁示例代碼分析

  • 在編譯階段插樁

  • 鏈接階段插樁

  • 執(zhí)行階段插樁

別人的經(jīng)驗,我們的階梯!

什么是插樁?

在稍微具有一點規(guī)模的代碼中(C 語言),調(diào)用第三方動態(tài)庫中的函數(shù)來完成一些功能,是很常見的工作場景。

假設(shè)現(xiàn)在有一項任務(wù):需要在調(diào)用某個動態(tài)庫中的某個函數(shù)的之前和之后,做一些額外的處理工作。

這樣的需求一般稱作:插樁,也就是對于一個指定的目標函數(shù),新建一個包裝函數(shù),來完成一些額外的功能。

在包裝函數(shù)中去調(diào)用真正的目標函數(shù),但是在調(diào)用之前或者之后,可以做一些額外的事情。

比如:統(tǒng)計函數(shù)的調(diào)用次數(shù)、驗證函數(shù)的輸入?yún)?shù)是否合法等等

關(guān)于程序插樁的官方定義,可以看一下【百度百科】中的描述:

  1. 程序插樁,最早是由J.C. Huang 教授提出的。

  2. 它是在保證被測程序原有邏輯完整性的基礎(chǔ)上在程序中插入一些探針(又稱為“探測儀”,本質(zhì)上就是進行信息采集的代碼段,可以是賦值語句或采集覆蓋信息的函數(shù)調(diào)用)。

  3. 通過探針的執(zhí)行并拋出程序運行的特征數(shù)據(jù),通過對這些數(shù)據(jù)的分析,可以獲得程序的控制流和數(shù)據(jù)流信息,進而得到邏輯覆蓋等動態(tài)信息,從而實現(xiàn)測試目的的方法。

  4. 根據(jù)探針插入的時間可以分為目標代碼插樁和源代碼插樁。

這篇文章,我們就一起討論一下:在 Linux 環(huán)境下的 C 語言開發(fā)中,可以通過哪些方法來實現(xiàn)插樁功能。

插樁示例代碼分析

示例代碼很簡單:

├── app.c
└── lib
├── rd3.h
└── librd3.so

假設(shè)動態(tài)庫librd3.so是由第三方提供的,里面有一個函數(shù):int rd3_func(int, int);

// lib/rd3.h

#ifndef _RD3_H_
#define _RD3_H_
extern int rd3_func(int, int);
#endif

在應(yīng)用程序app.c中,調(diào)用了動態(tài)庫中的這個函數(shù):

app.c代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include "rd3.h"

int main(int argc, char *argv[])
{
int result = rd3_func(1, 1);
printf("result = %d \n", result);
return 0;
}

編譯:

$ gcc -o app app.c -I./lib -L./lib -lrd3 -Wl,--rpath=./lib
  1. -L./lib: 指定編譯時,在 lib 目錄下搜尋庫文件。

  2. -Wl,--rpath=./lib: 指定執(zhí)行時,在 lib 目錄下搜尋庫文件。

生成可執(zhí)行程序:app,執(zhí)行:

$ ./app
result = 3

示例代碼足夠簡單了,稱得上是helloworld的兄弟版本!

在編譯階段插樁

對函數(shù)進行插樁,基本要求是:不應(yīng)該對原來的文件(app.c)進行額外的修改

由于app.c文件中,已經(jīng)include "rd3.h"了,并且調(diào)用了其中的rd3_func(int, int)函數(shù)。

所以我們需要新建一個假的 "rd3.h" 提供給app.c,并且要把函數(shù)rd3_func(int, int)"重導(dǎo)向"到一個包裝函數(shù),然后在包裝函數(shù)中去調(diào)用真正的目標函數(shù),如下圖所示:

"重導(dǎo)向"函數(shù):可以使用宏來實現(xiàn)。

包裝函數(shù):新建一個C文件,在這個文件中,需要 #include "lib/rd3.h",然后調(diào)用真正的目標文件。

完整的文件結(jié)構(gòu)如下:

├── app.c
├── lib
│   ├── librd3.so
│   └── rd3.h
├── rd3.h
└── rd3_wrap.c

最后兩個文件是新建的:rd3.h, rd3_wrap.c,它們的內(nèi)容如下:

// rd3.h

#ifndef _LIB_WRAP_H_
#define _LIB_WRAP_H_

// 函數(shù)“重導(dǎo)向”,這樣的話 app.c 中才能調(diào)用 wrap_rd3_func
#define rd3_func(a, b) wrap_rd3_func(a, b)

// 函數(shù)聲明
extern int wrap_rd3_func(int, int);

#endif
// rd3_wrap.c

#include <stdio.h>
#include <stdlib.h>

// 真正的目標函數(shù)
#include "lib/rd3.h"

// 包裝函數(shù),被 app.c 調(diào)用
int wrap_rd3_func(int a, int b)
{
// 在調(diào)用目標函數(shù)之前,做一些處理
printf("before call rd3_func. do something... \n");

// 調(diào)用目標函數(shù)
int c = rd3_func(a, b);

// 在調(diào)用目標函數(shù)之后,做一些處理
printf("after call rd3_func. do something... \n");

return c;
}

app.c 和 rd3_wrap.c一起編譯:

$ gcc -I./ -L./lib -Wl,--rpath=./lib -o app app.c rd3_wrap.c -lrd3

頭文件的搜索路徑不能錯:必須在當(dāng)前目錄下搜索rd3.h,這樣的話,app.c中的#include "rd3.h" 找到的才是我們新增的那個頭文件 rd3.h

所以在編譯指令中,第一個選項就是 -I./,表示在當(dāng)前目錄下搜尋頭文件。

另外,由于在rd3_wrap.c文件中,使用#include "lib/rd3.h"來包含庫中的頭文件,因此在編譯指令中,就不需要指定到lib 目錄下去查找頭文件了。

編譯得到可執(zhí)行程序app,執(zhí)行一下:

$ ./app 
before call rd3_func. do something...
after call rd3_func. do something...
result = 3

完美!

鏈接階段插樁

Linux 系統(tǒng)中的鏈接器功能是非常強大的,它提供了一個選項:--wrap f,可以在鏈接階段進行插樁

這個選項的作用是:告訴鏈接器,遇到f符號時解析成__wrap_f,在遇到__real_f符號時解析成f,正好是一對!

我們就可以利用這個屬性,新建一個文件rd3_wrap.c,并且定義一個函數(shù)__wrap_rd3_func(int, int),在這個函數(shù)中去調(diào)用__real_rd3_func函數(shù)。

只要在編譯選項中加上-Wl,--wrap,rd3_func, 編譯器就會:

  1. 把 app.c 中的 rd3_func 符號,解析成 __wrap_rd3_func,從而調(diào)用包裝函數(shù);

  2. 把 rd3_wrap.c 中的 __real_rd3_func 符號,解析成 rd3_func,從而調(diào)用真正的函數(shù)。

這幾個符號的轉(zhuǎn)換,是由鏈接器自動完成的!

按照這個思路,一起來測試一下。

文件目錄結(jié)構(gòu)如下:

.
├── app.c
├── lib
│   ├── librd3.so
│   └── rd3.h
├── rd3_wrap.c
└── rd3_wrap.h

rd3_wrap.h是被app.c引用的,內(nèi)容如下:

#ifndef _RD3_WRAP_H_
#define _RD3_WRAP_H_
extern int __wrap_rd3_func(int, int);
#endif

rd3_wrap.c的內(nèi)容如下:

#include <stdio.h>
#include <stdlib.h>

#include "rd3_wrap.h"

// 這里不能直接飲用 lib/rd3.h 中的函數(shù)了,而要由鏈接器來完成解析。
extern int __real_rd3_func(int, int);

// 包裝函數(shù)
int __wrap_rd3_func(int a, int b)
{
// 在調(diào)用目標函數(shù)之前,做一些處理
printf("before call rd3_func. do something... \n");

// 調(diào)用目標函數(shù),鏈接器會解析成 rd3_func。
int c = __real_rd3_func(a, b);

// 在調(diào)用目標函數(shù)之后,做一些處理
printf("after call rd3_func. do something... \n");

return c;
}

rd3_wrap.c中,不能直接去 include "rd3.h",因為lib/rd3.h中的函數(shù)聲明是int rd3_func(int, int);,沒有__real前綴。

編譯一下:

$ gcc -I./lib -L./lib -Wl,--rpath=./lib -Wl,--wrap,rd3_func -o app app.c rd3_wrap.c -lrd3

注意:這里的頭文件搜索路徑仍然設(shè)置為-I./lib,是因為app.cinclude了這個頭文件

得到可執(zhí)行程序app,執(zhí)行:

$ ./app
before call rd3_func. do something...
before call rd3_func. do something...
result = 3

完美!


執(zhí)行階段插樁

編譯階段插樁,新建的文件rd3_wrap.c是與app.c一起編譯的,其中的包裝函數(shù)名是wrap_rd3_func

app.c中通過一個宏定義實現(xiàn)函數(shù)的"重導(dǎo)向"rd3_func --> wrap_rd3_func

我們還可以直接"霸王硬上弓":在新建的文件rd3_wrap.c中,直接定義rd3_func函數(shù)。

然后在這個函數(shù)中通過dlopen, dlsym系列函數(shù)來動態(tài)的打開真正的動態(tài)庫,查找其中的目標文件,然后調(diào)用真正的目標函數(shù)。

當(dāng)然了,這樣的話在編譯app.c時,就不能連接lib/librd3.so文件了。

按照這個思路繼續(xù)實踐!

文件目錄結(jié)構(gòu)如下:

├── app.c
├── lib
│   ├── librd3.so
│   └── rd3.h
└── rd3_wrap.c

rd3_wrap.c文件的內(nèi)容如下(一些錯誤檢查就暫時忽略了):

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

// 庫的頭文件
#include "rd3.h"

// 與目標函數(shù)簽名一致的函數(shù)類型
typedef int (*pFunc)(int, int);

int rd3_func(int a, int b)
{
printf("before call rd3_func. do something... \n");

//打開動態(tài)鏈接庫
void *handle = dlopen("./lib/librd3.so", RTLD_NOW);

// 查找?guī)熘械哪繕撕瘮?shù)
pFunc pf = dlsym(handle, "rd3_func");

// 調(diào)用目標函數(shù)
int c = pf(a, b);

// 關(guān)閉動態(tài)庫句柄
dlclose(handle);

printf("after call rd3_func. do something... \n");
return c;
}

編譯包裝的動態(tài)庫

$ gcc -shared -fPIC -I./lib -o librd3_wrap.so rd3_wrap.c

得到包裝的動態(tài)庫: librd3_wrap.so

編譯可執(zhí)行程序,需要鏈接包裝庫 librd3_wrap.so

$ gcc -I./lib -L./ -o app app.c -lrd3_wrap -ldl

得到可執(zhí)行程序app,執(zhí)行:

$ ./app 
before call rd3_func. do something...
after call rd3_func. do something...
result = 3

完美!


往期推薦



探索CPU的調(diào)度原理

防御性編程技巧

C++的全鏈路追蹤方案,稍微有點高端

多線程程序中操作的原子性

C++反射TS初探

喵哥吐血整理:軟件開發(fā)的51條建議

為什么公司寧可高薪招一個新員工,也不愿意給老員工漲一點工資?

函數(shù)返回值的行業(yè)潛規(guī)則

模版定義一定要寫在頭文件中嗎?

為什么建議少用if語句!

四萬字長文,這是我見過最好的模板元編程文章!


亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美啪啪一区| 欧美激情一区二区三区高清视频 | 在线视频欧美日韩精品| 亚洲激情影视| 激情久久久久久久| 亚洲国产成人高清精品| 国内精品美女在线观看| 国产一区av在线| 国产视频一区免费看| 国产精品亚洲综合一区在线观看 | 国产一区二区三区奇米久涩 | 国产精品video| 欧美肉体xxxx裸体137大胆| 欧美成人69av| 欧美视频在线观看一区| 欧美激情一区二区三区高清视频| 欧美精选午夜久久久乱码6080| 国产午夜亚洲精品羞羞网站 | 欧美日韩另类一区| 欧美色精品天天在线观看视频| 国产精品女主播一区二区三区| 亚洲国产经典视频| 久久亚洲欧美国产精品乐播| 亚洲国产欧美日韩另类综合| 久久综合影音| 在线观看欧美视频| 欧美日韩国产小视频在线观看| 日韩网站在线| 欧美精品成人在线| 亚洲伊人观看| 黄色一区二区三区四区| 久久精品欧美日韩| 国产欧美日韩视频一区二区三区| 日韩视频中文| 亚洲视频网在线直播| 你懂的网址国产 欧美| 国产精品色网| 在线视频日韩| 欧美色欧美亚洲另类七区| 国产一区二区三区久久久| 蜜臀99久久精品久久久久久软件| 国精产品99永久一区一区| 久久精品国产精品亚洲| 欧美美女视频| 亚洲综合99| 亚洲人成在线观看| 久久免费国产| 国内精品美女av在线播放| 亚洲黄色尤物视频| 久久免费一区| 在线综合亚洲| 欧美日韩亚洲另类| 久久精品伊人| 一区二区三区四区五区精品| 国产精品都在这里| 亚洲在线黄色| 久久嫩草精品久久久久| 欧美一级专区免费大片| 夜久久久久久| 亚洲美女在线视频| 伊人久久婷婷色综合98网| 欧美日韩一二区| 欧美另类视频| 美国十次了思思久久精品导航| 亚洲最新在线视频| 91久久国产综合久久| 影音先锋日韩资源| 国产精品资源在线观看| 国产精品一区=区| 国产精品久99| 国产精品入口| 国产精品久久久久久久午夜| 国产精品日韩一区二区| 国产伦精品免费视频| 国产日韩专区| 在线欧美三区| 在线亚洲观看| 久久激情视频| 欧美理论电影在线播放| 欧美日韩另类字幕中文| 欧美午夜精品| 国产无一区二区| 国产精品视频网| 国产日韩在线一区二区三区| 国产亚洲一区二区三区在线观看| 国产欧美日韩视频一区二区| 国产亚洲激情在线| 国产欧美日韩精品在线| 韩国福利一区| 最新中文字幕一区二区三区| 亚洲福利一区| 亚洲欧洲在线视频| 韩国福利一区| 国产在线精品一区二区中文| 国产麻豆9l精品三级站| 国产精品少妇自拍| 日韩香蕉视频| 性欧美暴力猛交69hd| 美腿丝袜亚洲色图| 国产精品一级| 亚洲区第一页| 一区二区三区精密机械公司| 免费不卡亚洲欧美| 国产精品v日韩精品| 国产亚洲精品bv在线观看| 亚洲福利国产精品| 亚洲欧美在线视频观看| 欧美高清视频在线播放| 国产欧美va欧美va香蕉在| 亚洲精品女人| 欧美乱人伦中文字幕在线| 91久久精品国产91久久| 老司机久久99久久精品播放免费 | 欧美激情在线播放| 一本色道久久88综合亚洲精品ⅰ | 一本久道综合久久精品| 国产精品蜜臀在线观看| 欧美精品福利| 亚洲视频在线视频| 欧美日韩另类在线| 在线亚洲精品| 欧美区二区三区| 国产欧美日韩一区二区三区在线观看| 尤物99国产成人精品视频| 麻豆乱码国产一区二区三区| 国产在线不卡精品| 久久av最新网址| 9色porny自拍视频一区二区| 国产精品私人影院| 女生裸体视频一区二区三区| 在线视频精品一区| 尤物yw午夜国产精品视频明星| 欧美亚洲一级| 国产精品男gay被猛男狂揉视频| 亚洲高清资源| 欧美另类高清视频在线| 亚洲在线观看视频| 亚洲国产精品女人久久久| 久久婷婷国产麻豆91天堂| 亚洲人精品午夜| 国产精品一区免费观看| 欧美成人免费观看| 久久gogo国模裸体人体| 亚洲激情六月丁香| 精品动漫3d一区二区三区免费版| 欧美国产三级| 亚洲欧美激情四射在线日| 亚洲第一精品夜夜躁人人躁| 欧美性猛交xxxx乱大交退制版 | 久久天天躁夜夜躁狠狠躁2022| 亚洲激情在线激情| 欧美日韩一区高清| 久久综合婷婷| 一区二区欧美激情| 亚洲国产mv| 欧美日韩1区2区| 亚洲精品久久久久久久久久久久| 伊人久久综合| 亚洲国产精品va在线看黑人动漫| 国产欧美在线观看| 久久影院午夜论| 亚洲欧美另类在线观看| 国产午夜精品麻豆| 久久综合网络一区二区| 欧美成人有码| 欧美精品尤物在线| 国产久一道中文一区| 在线观看日韩一区| 亚洲精品在线视频| 亚洲乱码日产精品bd| 在线亚洲免费| 国产欧美一区二区三区在线看蜜臀| 国产精品成人免费| 欧美亚州一区二区三区| 欧美视频四区| 激情综合中文娱乐网| 欧美激情综合| 欧美一区成人| 久久久亚洲人| 欧美视频1区| 在线免费观看欧美| 日韩午夜av在线| 欧美一区视频| 欧美日韩一区二区三区免费| 国产精品视屏| 亚洲精品视频在线看| 久久久美女艺术照精彩视频福利播放 | 国产日韩欧美综合| 99综合在线| 免费在线国产精品| 国产一区二区精品在线观看| 亚洲欧美日韩精品久久| 欧美日韩不卡在线| 亚洲国产视频直播| 久久国内精品自在自线400部| 欧美日韩中文| 日韩午夜一区| 欧美高清视频一区二区| 亚洲日韩欧美一区二区在线| 久久精品夜色噜噜亚洲a∨|