手動跟蹤函數的調用過程

來源:互聯網
上載者:User

           今天是10月13號,不知道為什麼日子過的如此的快,大概是假期的原因吧。在十一國慶以後,上了3天課又放假了...感覺研究生的生活越來越沒有學生樣子啦...老師在很久以前就安排了一個任務給我,叫我完成在arm板子上的視頻顯示,做過了前期的JPEG的顯示,覺得這個問題本身不是很大。大概是自己對這種事情瞭解的太少,當真正的去接觸的時候就覺得難度很大。


            視頻本身是有一幀一幀的資料群組成,一幀其實可以看成是一張圖片,所以說直白點就是讓很多張圖片,在一秒內一張一張的顯示,因為人類眼睛的視覺暫留的特性,在一個頻率的情況下就會形成動態效果。可以如果真的這樣儲存資料的話那樣一個很多的視頻的資料量也是很大很大的,所以就要對視頻進行壓縮。老師給與的任務竟然是視頻的播放,難道是要做播放器,視頻的壓縮,我的天啊,我突然覺得自己壓力很大...那個時候才真正的感覺到team
work的重要性,就像很多程式員一樣,都是比較相信自己的能力,也比較獨立的,很多事情不喜歡讓別人去做,或者對別人做的事情不相信之類的,什麼事情都是親曆親為的,當然我也是一樣,很多的東西我喜歡自己完成,自己做的東西才能讓自己感覺是對的。可是當項目很大的事情,你會覺得自己很無力,覺得自己看著後面還有那麼多的東西要寫的時候,你會覺得自己真的不想做。這樣就超級容易想放棄的衝動!很多大牛寫的東西都很大很大,覺得真的很佩服他們,或者他們真的找到了自己喜歡的東西。關於視頻的播放在拖了一段時間以後,老師來看我的進展的時候我和他說了自己的想法,他給予的意見是他不需要我做什麼播放器或者是解碼器,只要我能會用現成的東西,於是就很偷懶的去網上下了一個庫,這是一個相當有名的庫哦(FFMPEG),花了不少時間在做移植上,感覺這個東西其實也很難的,很多東西不對,很多東西和別人說的有差別,感覺這個事情必須在自己很冷靜的情況下去做,在我偉大的EQ支援下,終於搞定了移植,程式是用他本身的那個例子,我唯一做的就是把我以前關於framebuffer的顯示功能給連結起來...這一切花了我不少時間,老師今天下午看了一下成果,好像還挺滿意的。說要把一個本科身的Face Service給移植過來,不過我不急,因為那個本科身本身也還沒寫好...可以空閑不少時間了,今天下午就打了一下午的醬油。


           說了那麼多最近的事情,都好像和題目沒有什麼關係,呵呵,關於這個題目,是在看<C專家編程>的一個編程挑戰題中看到的。其實一開始看見這個題的時候我不會,連一點想法都沒有,感覺自己還算太嫩了點.很多關於C的東西我都不是清楚的,狀況是我知道他們也知道,他們知道我並不一定知道的狀況,慚愧啊.....所以就很傷心了...

先說一下最近網易的一個筆試題目吧,我一同學和我說的,話說網易這個公司是我比較喜歡的,根據我的瞭解還有朋友的介紹,相對其他同等層級的公司,網易這個公司的企業文化還不錯,當然我還沒去過,也不清楚...而且它只對浙大校招,讓我很嚮往這個公司,哈哈....又跑題了,這個問題好像是這樣的,讓你寫一個程式,你怎麼輸出他的行號,函數名,檔案名稱等,其實這個問題你知道的人其實很簡單,不知道的人打死你也想不出來的。這就是幾個宏而已,__LINE__,__FUNCTION__,__FILE__這些宏。所以我覺得在編程的道路上一定要有一種好奇心,那樣才能讓你學的越多,知識面越廣...正如某某人說的“細節決定一切”。

關於上面的這個題目的答案其實我在上個月我也碰見過,不過好像這回事情沒有激起我的興趣,所以他就被我忽略了...真不好意思啊...哈哈哈...以後不會這樣了!話說網易竟然考了這題,讓我很想知道編譯器還定義了其他什麼宏,google了一下,搜尋到了兩個函數,這個讓我很驚訝,也讓我有衝動去完成書中的題目。

這個兩個函數就是:

void __cyg_profile_func_enter(void *funaddr, void *callsite)__attribute__((no_instrument_function));

void __cyg_profile_func_exit(void *funaddr, void *callsite)__attribute__((no_instrument_function));

          這兩個函數的作用是,當你調用一個函數的時候它會自動的調用 __cyg_profile_func_enter,而當程式離開函數的時候他會調用__cyg_profile_func_exit這個函數。其實當你碰到書中的題目的時候,唯一的難度就是在於函數的調用的時候怎麼去識別,如果你對每一個你寫過的函數你都寫入輸入輸出,那麼就是一個改動相當巨大的事情,而且這使得你必須去改變你的原始碼了,所以難題就是怎麼樣去識別函數的調用過程,而這兩個函數不是正好就體現了這個功能嗎???所以當我看見這兩個函數的時候我很興奮!!先讓我介紹這兩個函數吧。

           這種現象是屬於GCC function instrumentation機制,這種機制出現在gcc2.x中,是一個有cygnus提出。所以要使用這種這些功能,必須在編譯的時候加上-finstrument-functions這個選項。都知道C語言實現調用是通過桟來實現的,那麼我們將函數調用過程中的過程記錄叫做call frame,而上述的兩個函數就是在進入函數時和退出函數時被調用。關於這個__attribute__這個東西我也不是很清楚,明天研究一下再說,不過這裡的no_instrument_function的作用為了防止進入__cyg_profile_func_enter函數時再次調用這個函數,然後就進入了無限遞迴的狀態。

            問題解決了一半,所以現在可以自動去識別函數的調用,但是要輸出函數名字,好象還有點問題,本以為可以使用上面幾個介紹的宏,可是現在主要在__cyg_profile_func_enter的函數中,所以這些宏都失效了。不過到現在你還不知道函數參數的具體含義吧,funaddr是函數的開始地址,而callsite則是返回地址,不知道有沒有什麼東西能將這些東西轉變為具體的行號。哈哈...我覺得我是幸運的,在前幾天看見了一個GCC的工具,是addr2line這個工具,這個工具能將地址轉變為對應的行號之類的,不過一些特別的地址好像是不能進行轉化的。可是這是一個具體的命令,不知道怎麼用到程式中來,還是一個問題,本來先進行輸出,然後再對輸出檔案進行shell

指令碼處理。不過好像又很幸運的在網上碰到了popen這個函數。 


FILE *popen(const char *command,const char *type);


           這個函數的好處是會建立一個管道,並且調用shell,type有兩種類型一種是“r” 另一種是“w”,這兩種的不同之處就再說r是讀管道,w是寫入管道,不過這兩個只能選擇其中一個,關鍵是這個是調用shell的,並且讓shell執行你的命令,那不是很符合我要的功能嗎。。。哈哈哈

忘記講一個東西了,那就是一個dladdr這個函數了,這個函數其實我也不怎麼清楚,所以讓我多行瞭解以後再說,不過這個函數的用處是可以通過一個函數地址,知道一個Dl_info 的結構體,

typedef struct {

const char *dli_fname;  /* Pathname of shared object that contains address */               void       *dli_fbase;  /* Address at which shared object is loaded */               const char *dli_sname;  /* Name of nearest symbol with address  lower than addr */               void       *dli_saddr;  /* Exact address of symbol named  in dli_sname */           } Dl_info;

關於dladdr這個函數我在我的下一篇文章已經翻譯了這函數參數的具體意思。

           昨天說了,下面這個函數好像對動態庫和靜態庫不能支援,不過經過剛才的研究發現,當你在編譯庫檔案的時候也顯示的使用-finstrument-funtions這個去編譯的話,最後是可以顯示出來的,不過問題是我們不能讓本身系統的庫在編譯的過程中加這個選項,所以不能訪問。其實這不是dladdr的錯,錯應該是上面那個紅色的函數沒有被調用的錯,所以還要繼續研究看看能不能繼續改進。不過時候dladdr可以顯示出動態庫中的訊息,相當強大的一個函數。

下面是code,好像是可以手動的追蹤函數的調用

#define _GNU_SOURCE#include <stdio.h>#include <dlfcn.h>#include <stdlib.h>#include <unistd.h>#include <string.h>//this func is called when your program has func is called//thiz is enter func address//callsite is func back address void __cyg_profile_func_enter(void *thiz, void *callsite)__attribute__((no_instrument_function));void __cyg_profile_func_exit(void *thiz, void *callsite)__attribute__((no_instrument_function));void display(void *enter, void *callsite, int flag)__attribute__((no_instrument_function));void display(void *enter, void *callsite, int flag){    Dl_info info;    char cmd[1024] = "addr2line  -e ";    char *ptr = cmd + strlen(cmd);    int strsize = readlink("/proc/self/exe",ptr,sizeof(cmd) - (ptr - cmd) - 1);    if(strsize == -1)    {fprintf(stderr,"readlink is failure!\n");exit(-1);    }    FILE *fp = popen(cmd,"w");    if(!fp)    {perror("popen\n");exit(-1);    }        if(dladdr(enter,&info) == 0)    {fprintf(stderr,"addr to funcname is failure\n");exit(-1);    }    //flag=1,enter or flag=0,exit    if(flag)    {char address[256];printf("\n-------------------------------------------\n");printf("your program has entered a function!\n");printf("this run filename is %s\n",info.dli_fname);printf("this function name is %s\n",info.dli_sname);printf("this function's address is %p\n",enter);printf("this function back row is \n");sprintf(address,"%p\0",callsite);fwrite(address,1,strlen(address) + 1,fp);    }    else    {printf("\n-------------------------------------------\n");printf("your program will leave this function %s\n",info.dli_sname);printf("-------------------------------------------\n");    }    pclose(fp);}void __cyg_profile_func_enter(void *thiz, void *callsite){    display(thiz,callsite,1);} void __cyg_profile_func_exit(void *thiz, void *callsite){    display(thiz,callsite,0);}

編譯的命令一定要加上-rdynamic  -finstrument-functions  的命令。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.