亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        基于ARM的Linux驅(qū)動(dòng)調(diào)試技術(shù)研究

        2016-09-26 07:20:28
        關(guān)鍵詞:進(jìn)程調(diào)試

        鞏 琛 蔡 文

        (上海師范大學(xué)信息與機(jī)電工程學(xué)院 上海 200234)

        ?

        基于ARM的Linux驅(qū)動(dòng)調(diào)試技術(shù)研究

        鞏琛蔡文

        (上海師范大學(xué)信息與機(jī)電工程學(xué)院上海 200234)

        在ARM上進(jìn)行Linux驅(qū)動(dòng)移植時(shí),要對(duì)Linux內(nèi)核代碼進(jìn)行修改、刪減或添加,但這樣做在運(yùn)行時(shí)可能會(huì)遇到很多意想不到的錯(cuò)誤,這時(shí)就需要去調(diào)試代碼以找到出錯(cuò)的原因和位置。針對(duì)這一需要,提出并實(shí)現(xiàn)兩種新的調(diào)試技術(shù):第一種構(gòu)造一個(gè)打印函數(shù),把添加的打印信息單獨(dú)存儲(chǔ),然后借助proc文件系統(tǒng)將其輸出,實(shí)現(xiàn)了外加打印信息與內(nèi)核自身打印信息的分離,使查找更加方便;其次利用系統(tǒng)時(shí)鐘中斷永不停息的特性確定系統(tǒng)僵死的位置。通過(guò)實(shí)驗(yàn)表明,該技術(shù)能快速有效地找到死循環(huán)的位置,省去了大量查找和分析代碼的工作。

        Linux調(diào)試proc文件系統(tǒng)系統(tǒng)時(shí)鐘中斷

        0 引 言

        如今,以ARM為核心處理器,搭載Linux操作系統(tǒng)的嵌入式產(chǎn)品越來(lái)越多,應(yīng)用場(chǎng)景越來(lái)越廣泛[1]。但由于硬件平臺(tái)的多樣性,并沒(méi)有一套通用的Linux操作系統(tǒng)。開發(fā)相應(yīng)的嵌入式產(chǎn)品時(shí),需要工程師根據(jù)硬件平臺(tái)外圍設(shè)備的特性對(duì)Linux內(nèi)核源碼進(jìn)行增減。這樣一個(gè)移植過(guò)程中會(huì)出現(xiàn)各種各樣的bug,此時(shí)就需要開發(fā)者運(yùn)用各種調(diào)試手段去找到出錯(cuò)的地方和原因。本文基于Linux+ARM的實(shí)驗(yàn)平臺(tái)(Linux選取2.6.31.14的版本;ARM架構(gòu)芯片采用三星公司的s3c2440;BootLoader采用U-boot,根文件系統(tǒng)用Busybox創(chuàng)建[2,3]),提出并實(shí)現(xiàn)兩種新的驅(qū)動(dòng)調(diào)試技術(shù)。文中涉及到的交叉開發(fā)方面的知識(shí)不作詳述。

        1 構(gòu)建proc文件輸出私有調(diào)試信息

        1.1整體思想概述

        在調(diào)試Linux驅(qū)動(dòng)時(shí)在程序里用printk()添加打印語(yǔ)句是最常用的方法[4]。首先,Linux內(nèi)核會(huì)在內(nèi)核空間分配一段靜態(tài)緩沖區(qū),作為顯示用的空間。然后調(diào)用sprintf,格式化顯示字符串,最后調(diào)用tty_write向終端進(jìn)行信息的顯示。執(zhí)行dmesg命令,就可把緩沖區(qū)里面的打印信息重新顯示在硬件終端上。dmesg命令的實(shí)質(zhì)是打開/proc/kmsg文件。

        Linux內(nèi)核源碼多用printk()打印信息,而開發(fā)人員在調(diào)試驅(qū)動(dòng)時(shí)也常常會(huì)用printk()添加調(diào)試信息。當(dāng)開發(fā)者想回頭查看自己添加的打印信息時(shí),用簡(jiǎn)單的cat命令去打開 /proc/kmsg文件即可。但此時(shí)顯示的是與內(nèi)核打印信息混雜在一起的結(jié)果,查找起來(lái)很不方便。cat命令的原理是先執(zhí)行open系統(tǒng)調(diào)用打開某個(gè)文件,然后再在一個(gè)while()里用read系統(tǒng)調(diào)用循環(huán)地讀取該文件里面的內(nèi)容,然后把內(nèi)容顯示到硬件輸出端。cat命令的機(jī)制原理不是本文的重點(diǎn),這里只是簡(jiǎn)單介紹一下,便于后面代碼的理解。

        基于此問(wèn)題,本文構(gòu)造出一個(gè)私有打印函數(shù)pvt_printk(),把自己添加的打印語(yǔ)句單獨(dú)存儲(chǔ)到一段緩沖區(qū)pvt_buf里面去。然后利用內(nèi)核的proc機(jī)制創(chuàng)建一個(gè)與kmsg類似的文件pvt_kmsg。當(dāng)去執(zhí)行cat/proc/pvt_kmsg時(shí),可把pvt_buf緩沖區(qū)里面的數(shù)據(jù)顯示出來(lái)。

        1.2proc文件系統(tǒng)

        本調(diào)試技術(shù)用到了Linux內(nèi)核的proc虛擬文件系統(tǒng),它是一種在用戶態(tài)檢查內(nèi)核狀態(tài)的機(jī)制。里面的內(nèi)容是內(nèi)核動(dòng)態(tài)生成的。它的存在主要是想通過(guò)這樣一種渠道把內(nèi)核的一些狀態(tài)信息反饋給用戶,讓用戶能夠了解到內(nèi)核運(yùn)行的一些狀況[5]。

        Linux內(nèi)核當(dāng)中使用structproc_dir_entry結(jié)構(gòu)體來(lái)表示和描述/proc目錄下的一個(gè)文件或者目錄。如下:

        structproc_dir_entry

        {

        …… ……

        conststructfile_operations*proc_fops;

        …… ……

        }

        這個(gè)結(jié)構(gòu)里面成員比較多,其他的不用太關(guān)心,這里著重介紹file_operations這個(gè)結(jié)構(gòu)體,它與對(duì)proc文件的具體操作相對(duì)應(yīng)[5]。Linux內(nèi)核當(dāng)中是用create_proc_entry這個(gè)函數(shù)去創(chuàng)建一個(gè)proc文件,返回值為一個(gè)proc_dir_entry結(jié)構(gòu)體指針。

        structproc_dir_entry*create_proc_entry(constchar

        *name,mode_tmode,structproc_dir_entry*parent)

        name: 要?jiǎng)?chuàng)建的文件名。

        mode: 要?jiǎng)?chuàng)建的文件屬性。

        parent: 這個(gè)文件的父目錄。如果為NULL,便直接在proc的根目錄下面去創(chuàng)建文件。

        file_operations這個(gè)結(jié)構(gòu)體的成員也很多,本文只用到open、read。

        structfile_operations

        {

        ……;

        ssize_t(*read) (structfile*,char__user*,size_t,loff_t*);

        ssize_t(*write) (structfile*,constchar__user*,size_t,loff_t*);

        int(*open) (structinode*,structfile*);

        ……;

        }

        當(dāng)應(yīng)用程序(本實(shí)驗(yàn)就是cat命令)對(duì)一個(gè)proc文件執(zhí)行open、read、write系統(tǒng)調(diào)用時(shí)[6],程序會(huì)通過(guò)SWI指令,最終調(diào)用到與此文件相對(duì)應(yīng)的file_operations結(jié)構(gòu)體里面的open、read、write函數(shù)。整個(gè)過(guò)程類似于一個(gè)典型的字符型設(shè)備驅(qū)動(dòng)[7],/proc目錄下的文件有點(diǎn)像字符型驅(qū)動(dòng)里面的設(shè)備節(jié)點(diǎn)。

        1.3實(shí)現(xiàn)過(guò)程及步驟

        創(chuàng)建proc-printk.c文件作為該實(shí)驗(yàn)的驅(qū)動(dòng)源碼文件。經(jīng)前面分析,用到proc文件的描述結(jié)構(gòu)體proc_dir_entry和創(chuàng)建函數(shù)create_proc_entry(),所以程序除了添加字符型驅(qū)動(dòng)所需的頭文件,還需要包含Linux/proc_fs.h。

        在驅(qū)動(dòng)初始化函數(shù)里利用create_proc_entry()去創(chuàng)建一個(gè)proc_dir_entry結(jié)構(gòu)體指針pvt_entry,并將其設(shè)為全局變量。如果創(chuàng)建成功,把file_operations結(jié)構(gòu)體proc_pvt_entry_operations的指針賦給pvt_entry所指結(jié)構(gòu)體里面的proc_fops成員。

        structproc_dir_entry*pvt_entry;

        staticintpvt_kmsg_init(void)

        {

        pvt_entry=create_proc_entry("pvt_kmsg",S_IRUSR,NULL);

        if(pvt_entry)

        pvt_entry->proc_fops=&proc_pvt_kmsg_operations;

        return0;

        }

        S_IRUSR是Linux內(nèi)核定義的宏,作用是讓創(chuàng)建的文件的屬性為只讀。

        staticvoidpvt_kmsg_exit(void)

        {

        remove_proc_entry("pvt_kmsg",NULL);/*在出口函數(shù)做相應(yīng)的移除*/

        }

        module_init(pvt_kmsg_init);

        module_exit(pvt_kmsg_exit);

        MODULE_LICENSE("GPL");

        接著構(gòu)造并填充file_operations結(jié)構(gòu)體proc_pvt_kmsg_operations。

        structfile_operationsproc_pvt_kmsg_operations=

        {

        .read=pvt_kmsg_read,

        .open=pvt_kmsg_open,

        };

        先實(shí)現(xiàn)pvt_kmsg_read函數(shù),pvt_kmsg_open后面再說(shuō)。

        staticssize_tpvt_kmsg_read(structfile*file,char__user*buf,size_tcount,loff_t*ppos)

        {

        inti,ret;

        charc;

        //文件以非阻塞方式打開并且pvt_buf為空,立刻返回錯(cuò)誤

        if((file->f_flags&O_NONBLOCK) &&empty())

        return-EAGAIN;

        //如果文件以阻塞方式打開又為空,用wait_event_interruptible()讓此進(jìn)程在queue等待隊(duì)列上睡眠[8]

        //如果文件以阻塞方式打開有數(shù)據(jù),用__put_user把數(shù)據(jù)讀到用戶空間

        if(!wait_event_interruptible(queue,!empty()))

        {

        for(i=0;i

        //count是要讀的字節(jié)數(shù)

        {

        if(read_pvt_buf(&c))

        {

        ret=__put_user(c,buf);

        //返回值:0表成功,-EFAULT表錯(cuò)誤

        buf++;

        }

        }

        }

        returnret;

        }

        上述代碼用等待隊(duì)列來(lái)實(shí)現(xiàn)阻塞操作,所以需在文件開頭用宏DECLARE_QUEUEEUE_HEAD(queue)去定義并初始化一個(gè)等待隊(duì)列queue。

        定義一個(gè)私有的存儲(chǔ)區(qū)域staticcharpvt_buf[2048],對(duì)它的存貯讀取方式采用數(shù)組環(huán)形緩沖區(qū)。在本設(shè)計(jì)里只有自定義的打印函數(shù)pvt_printk()往里寫數(shù)據(jù),只有cat應(yīng)用程序從里讀數(shù)據(jù)。在這樣僅有一個(gè)讀用戶和一個(gè)寫用戶的情況下,使用環(huán)形緩沖區(qū)的好處是可以不用添加互斥[9]保護(hù)機(jī)制就能保證數(shù)據(jù)的正確性。下面是對(duì)環(huán)形緩沖區(qū)空、滿判斷函數(shù)和讀寫函數(shù)的實(shí)現(xiàn)。

        staticcharpvt_buf[2048];

        staticintread_p;

        staticintwrite_p= 0;

        staticintreadstart_p=0;

        //每次讀的起始位置

        staticintempty()

        {

        if(read_p==write_p)return1;

        elsereturn0;

        }

        staticintfull()

        {

        if((write_p+ 1)%2048 ==readstart_p)return1;

        elsereturn0;

        }

        staticvoidwrite_pvt_buf(charc)

        { /*如果數(shù)據(jù)滿了移動(dòng)一位讀的起始位,丟棄一個(gè)數(shù)據(jù) */

        if(full())

        readstart_p= (readstart_p+ 1) % 2048;

        pvt_buf[write_p] =c;

        write_p= (write_p+ 1) % 2048;

        wake_up_interruptible(&queue);

        //喚醒進(jìn)程

        }

        staticintread_pvt_buf(char*p)

        {

        if(empty())return0;

        *p=pvt_buf[read_p];

        read_p= (read_p+1) % 2048;

        return1;

        }

        接著實(shí)現(xiàn)私有打印函數(shù)pvt_printk。這里借助于內(nèi)核提供的vsnprintf函數(shù)的存儲(chǔ)功能進(jìn)行改寫。intvsnprintf(char*buf,size_tsize,constchar*fmt,va_listargs)把fmt指向的打印內(nèi)容拷貝到*buf里面。

        但為了實(shí)現(xiàn)環(huán)形緩沖區(qū)的順序?qū)懭耄@里不能直接將打印信息拷貝到pvt_buf。而是需先把打印信息存儲(chǔ)到這個(gè)臨時(shí)緩沖區(qū)temp[2048],再把臨時(shí)緩沖區(qū)的信息拷貝到pvt_buf。

        staticchartemp[2048];

        intpvt_printk(constchar*fmt,…)

        {

        va_listargs;

        intj,k= 0;

        va_start(args,fmt);

        /*把打印信息放到臨時(shí)緩沖區(qū)*/

        j=vsnprintf(temp,INT_MAX,fmt,args);

        va_end(args);

        /*把臨時(shí)緩沖區(qū)的數(shù)據(jù)放到環(huán)形緩沖區(qū)pvt_buf里 */

        while(k

        write_pvt_buf(temp[k]);

        k++;

        }

        returnj;

        }

        到此最初的構(gòu)想已經(jīng)可以實(shí)現(xiàn)了,但是這樣做只能cat一次。因?yàn)樵赾at一次后讀位置已經(jīng)移動(dòng)到最后面沒(méi)有數(shù)據(jù)的地方。所以為了實(shí)現(xiàn)多次可讀,得在每次cat調(diào)用open的時(shí)候把讀位置調(diào)整到起始的地方。

        staticintpvt_kmsg_open(structinode*inode,structfile*file)

        {

        read_p=readstart_p;

        return0;

        }

        用EXPORT_SYMBOL(pvt_printk)將pvt_printk函數(shù)導(dǎo)出,供全部?jī)?nèi)核文件使用。

        簡(jiǎn)單測(cè)試:在xx驅(qū)動(dòng)源碼里先用externintpvt_printk(constchar*fmt,…);聲明,然后在合適位置添加pvt_printk(“abcdefg”),將此驅(qū)動(dòng)和proc-printk.c都編譯進(jìn)內(nèi)核,把新內(nèi)核燒寫到ARM開發(fā)板并啟動(dòng)。在開發(fā)板的串口終端下先運(yùn)行與xx驅(qū)動(dòng)對(duì)應(yīng)的應(yīng)用程序test1,再去cat創(chuàng)建的proc文件pvt_kmsg,就可以看到添加的信息。如圖1所示。

        圖1 第一種調(diào)試方法實(shí)驗(yàn)結(jié)果

        2 利用內(nèi)核時(shí)鐘中斷確定僵死位置

        2.1原理

        當(dāng)驅(qū)動(dòng)程序某個(gè)地方不小心寫入了死循環(huán)的代碼。那么在運(yùn)行相應(yīng)app的時(shí)候Linux系統(tǒng)就會(huì)出現(xiàn)僵死的狀態(tài)。如果在多進(jìn)程的狀況話,直接追查代碼找尋僵死點(diǎn)那將顯得非常困難。

        但Linux時(shí)鐘中斷確是永遠(yuǎn)都在發(fā)生的,進(jìn)程的僵死是不會(huì)屏蔽掉系統(tǒng)時(shí)鐘中斷的。就像人一樣,即便是在睡覺,心臟總是在跳動(dòng)的。

        Linux系統(tǒng)下的中斷處理過(guò)程如圖2所示。t是時(shí)間軸,一個(gè)進(jìn)程在運(yùn)行著,發(fā)生中斷時(shí),先保存現(xiàn)場(chǎng),再執(zhí)行中斷函數(shù),最后回復(fù)現(xiàn)場(chǎng)[10],只不過(guò)系統(tǒng)時(shí)鐘中斷是周而復(fù)始的這樣執(zhí)行。

        圖2 中斷發(fā)生過(guò)程

        保存現(xiàn)場(chǎng)其實(shí)就是保存各個(gè)寄存器的值。其中pc寄存器(ARM里由r15寄存器充當(dāng))就保存了執(zhí)行中的驅(qū)動(dòng)程序被打斷處的地址。僵死狀態(tài)時(shí),進(jìn)程會(huì)重復(fù)執(zhí)行同一段代碼,這樣pc值會(huì)在一個(gè)很小的范圍里變動(dòng)。

        本調(diào)試技術(shù)就是借助系統(tǒng)時(shí)鐘中斷永不停息這一特性,在中斷入口函數(shù)里添加一些打印語(yǔ)句,把保存的pc值打印出來(lái),再經(jīng)過(guò)分析判斷定位出僵死的大致位置了。

        在本實(shí)驗(yàn)平臺(tái)的Linux系統(tǒng)當(dāng)中,一發(fā)生中斷,CPU就強(qiáng)制跳到0xffff0018處(此地址根據(jù)CPU的架構(gòu)不同而不同)執(zhí)行異常向量表里面的bvector_irq+stubs_offset。其中“stubs_offset”用來(lái)重定位跳轉(zhuǎn)的位置[11],這條匯編指令是去跳轉(zhuǎn)執(zhí)行vector_irq這個(gè)函數(shù),在這個(gè)函數(shù)里面保存了一些現(xiàn)場(chǎng),并經(jīng)過(guò)復(fù)雜的匯編代碼后會(huì)調(diào)用到asm_do_IRQ(archarmkernelIrq.c)這個(gè)函數(shù)。它是中斷處理函數(shù)的總?cè)肟赱12],在它內(nèi)部經(jīng)過(guò)層層的函數(shù)調(diào)用后,會(huì)最終執(zhí)行到時(shí)鐘中斷處理函數(shù)s3c2410_timer_interrupt()(archarmplat-s3c24xx ime.c)。選擇在s3c2410_timer_interrupt()或asm_do_IRQ()里加打印信息都可以,這里選擇asm_do_IRQ(),因?yàn)樵赼sm_do_IRQ()的傳入?yún)?shù)中有一個(gè)pt_regs結(jié)構(gòu)體,它作用就是保存發(fā)生中斷時(shí)的現(xiàn)場(chǎng)。pt_regs結(jié)構(gòu)體里面定義了一個(gè)長(zhǎng)度為18的數(shù)組uregs,其中uregs[15]保存的就是pc寄存器的值,正好可以利用它把pc值打印出來(lái)。但這里需注意一點(diǎn),中斷保存的pc值其實(shí)是實(shí)際指令地址+4。

        asmlinkagevoid__exceptionasm_do_IRQ(unsignedintirq,structpt_regs*regs)

        structpt_regs{

        longuregs[18];

        };

        ……

        #defineARM_pcuregs[15]

        ……

        2.2實(shí)現(xiàn)步驟

        先在一個(gè)正確的驅(qū)動(dòng)程序里加入一段死循環(huán)代碼。本文在mydrive.c這個(gè)驅(qū)動(dòng)源碼的讀函數(shù)mydrive_read()里加一句for(;;)。

        staticssize_tmydrive_read(structfile*file,constchar__user*buf,size_tcount,loff_t*ppos)

        {……

        for(;;);

        ……

        }

        然后把mydrive.c編譯成模塊下載到開發(fā)板(這里把驅(qū)動(dòng)程序編譯成模塊,直接編譯進(jìn)內(nèi)核的情況比較簡(jiǎn)單,后面會(huì)敘述)。insmodmydrive.ko后,執(zhí)行于此驅(qū)動(dòng)相對(duì)應(yīng)的測(cè)試程序mytest,就會(huì)看到系統(tǒng)完全卡死了。

        在asm_do_IRQ()函數(shù)里添加如下一段代碼,把僵死進(jìn)程號(hào)和pc值打印出來(lái)。

        staticpid_tpid;

        //之前進(jìn)程號(hào)

        staticintcount=0;

        If(irq== 30)

        //系統(tǒng)時(shí)鐘中斷用的是定時(shí)器4,對(duì)應(yīng)的中斷號(hào)是30

        {

        //若當(dāng)前進(jìn)程不等于之前進(jìn)程,計(jì)數(shù)值清零

        if(pid!=current->pid)

        {

        pid=current->pid;

        count= 0;

        }

        //當(dāng)前進(jìn)程等于之前的進(jìn)程,計(jì)數(shù)值累加

        else

        count++;

        if(count==15*HZ)若15秒內(nèi)都是同一個(gè)進(jìn)程

        {

        count= 0;

        printk(“PID=%d,name=%s,pc=%08x ”,current->pid,current->comm,regs->uregs[15]);

        }

        }

        在Linux內(nèi)核里面每一個(gè)進(jìn)程都由一個(gè)task_struct結(jié)構(gòu)體來(lái)表示[13,14],里面包含了進(jìn)程的相關(guān)屬性和信息。其中pid_tpid表示進(jìn)程號(hào);charcomm表示進(jìn)程的名字。

        current是一個(gè)全局宏,用來(lái)獲取表示當(dāng)前進(jìn)程的task_struct結(jié)構(gòu)體指針。HZ也是一個(gè)宏定義,表示時(shí)鐘中斷發(fā)生的頻率,即一秒發(fā)生中斷的次數(shù)。

        把修改的內(nèi)核源碼在Linux服務(wù)器下編譯后下載到開發(fā)板并啟動(dòng)。然后裝載驅(qū)動(dòng)模塊mydrive.ko并運(yùn)行與之相應(yīng)的測(cè)試程序mytest,如圖3所示。

        圖3執(zhí)行步驟

        系統(tǒng)僵死,等待15秒左右之后打印出僵死進(jìn)程號(hào)、僵死進(jìn)程名、

        pc

        值。如圖4所示。

        圖4 僵死進(jìn)程相關(guān)信息

        從打印信息可知是763號(hào)進(jìn)程mytest出現(xiàn)了僵死,從而可以知道問(wèn)題出在與mytest對(duì)應(yīng)的驅(qū)動(dòng)程序mydrive。在開發(fā)板的串口終端下打開system.map(里面是內(nèi)核的地址空間),發(fā)現(xiàn)bf000068不在其中,說(shuō)明僵死驅(qū)動(dòng)mydrive是個(gè)外加驅(qū)動(dòng)模塊,這也與實(shí)際操作相符。

        至于死循環(huán)代碼的具體位置還得用pc值去反推。在Linux2.6版本內(nèi)核中引入了kallsyms,kallsyms抽取了內(nèi)核用到的所有函數(shù)地址(全局的、靜態(tài)的)和非棧數(shù)據(jù)變量地址,生成一個(gè)數(shù)據(jù)塊,作為只讀數(shù)據(jù)鏈接進(jìn)kernelimage。當(dāng)然外加驅(qū)動(dòng)模塊的地址也在其中重啟開發(fā)板,在終端下執(zhí)行:

        insmodmydrive.ko

        cat/proc/kallsyms

        在里面尋找地址bf000068,就找到與bf000068相近的一條bf000000。

        bf000000tmydrive_open[mydrive]

        在Linux服務(wù)器下把mydrive.ko模塊反匯編arm-Linux-cbjdump-Dmydrive.ko>mydrive.dis

        打開mydrv.dis,找到有mydrive_open的那一行00000000,發(fā)現(xiàn)mydriver_open在單獨(dú)的匯編文件[15]中對(duì)應(yīng)地址是00000000,而當(dāng)mydrive.ko加載到內(nèi)核之后mydrive_open對(duì)應(yīng)地址變?yōu)閎f000000。pc值bf000068與它相比大了0x68,所以在單獨(dú)的匯編文件first_drv.dis中地址0x00000000+0x68就是與pc相對(duì)應(yīng)的值。

        00000000 :

        ……

        64:ebfffffebl64

        68:ea00001fbf8

        ……

        前面說(shuō)過(guò),中斷保存的pc值其實(shí)是實(shí)際指令地址+4,所以0x00000064才是中斷函數(shù)執(zhí)行前保存的真正地址,也即僵死的位置。再看對(duì)應(yīng)的名字mydrive_read+0x3c,可知具體代碼在mydrive_read()函數(shù)入口地址偏移0x3c。至此回到源碼文件mydrive.c的mydrive_read()函數(shù)便可找到具體的僵死處。這正好與之前故意添加的死循環(huán)for(;;)的位置相一致。比照著相應(yīng)的匯編指令[16]bl64:永遠(yuǎn)跳轉(zhuǎn)到64。這也剛好和死循環(huán)的C語(yǔ)言是相吻合的。

        這里的僵死點(diǎn)在外加的驅(qū)動(dòng)模塊中,如果僵死點(diǎn)在內(nèi)核里,就會(huì)發(fā)現(xiàn)打印出來(lái)的pc值在system.map文件所列出的地址范圍里面。這時(shí)只需要把使用的Linux內(nèi)核文件反匯編,在里面找到pc-4地址所在那一行代碼,自然就是僵死點(diǎn)的位置。

        3 結(jié) 語(yǔ)

        第一種調(diào)試方法中將驅(qū)動(dòng)源碼文件proc-printk.c編譯進(jìn)了內(nèi)核。當(dāng)然為了裝卸載方便,也可以將其編譯成模塊。在第二種調(diào)試方法中,為了測(cè)試需要,故意在驅(qū)動(dòng)文件里添加for(;;)語(yǔ)句,造成程序僵死在一點(diǎn),只打印出一個(gè)pc值。而在實(shí)際中,死循環(huán)的代碼可能是一段,這時(shí)用上述方法在一段時(shí)間內(nèi)打印出來(lái)的pc值可能會(huì)不同。但這不要緊,因?yàn)榇藭r(shí)的pc值雖不同,但分布密集。程序員只須分析這幾個(gè)pc值指定的匯編代碼就可確定僵死的大致位置。

        [1] 霍玲玲,王世君,徐曉卉,等.嵌入式Linux系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J]. 計(jì)算機(jī)技術(shù)與發(fā)展,2014,24(5):87-89.

        [2] 馮開林,劉春艷,韓東旭.基于S3C2440平臺(tái)搭建Linux環(huán)境[J]. 通信技術(shù),2013,46(11):120-124.

        [3] 付陽(yáng).基于ARM9的嵌入式Linux移植和驅(qū)動(dòng)程序設(shè)計(jì)[D].武漢:華中科技大學(xué),2012.

        [4] 韋東山.嵌入式Linux應(yīng)用開發(fā)完全手冊(cè)[M].北京:人民郵電出版社,2008.

        [5] 趙付強(qiáng),李允俊,宮彥磊.Proc文件系統(tǒng)的研究與應(yīng)用[J]. 計(jì)算機(jī)系統(tǒng)應(yīng)用,2013,22(1):87-90.

        [6] 郭銳.基于覆蓋測(cè)試的Linux內(nèi)核裁剪[D].太原:中北大學(xué),2014.

        [7] 宋寶華.Linux設(shè)備驅(qū)動(dòng)開發(fā)詳解[M].北京:人民郵電出版社,2010.

        [8] 王維,李濤,韓俊剛. 一種多線程輕核機(jī)器中進(jìn)程管理的硬件實(shí)現(xiàn)[J].電子技術(shù)應(yīng)用,2013,29(3):40-43.

        [9] 唐富強(qiáng),于鴻洋,張萍.Linux下通用線程池的改進(jìn)與實(shí)現(xiàn)[J].計(jì)算機(jī)工程與應(yīng)用,2012,48(28):77-83.

        [10] 周峰,胡軍山,朱宗玖.基于CK810LINUX3.0內(nèi)核的移植實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用與軟件,2014,31(1):252-255,267.

        [11] 鄭強(qiáng).Linux驅(qū)動(dòng)開發(fā)入門與實(shí)戰(zhàn)[M].北京:清華大學(xué)出版社,2011.

        [12] 毛德操,胡希明.Linux內(nèi)核源代碼情景分析[M].杭州:浙江大學(xué)出版社,2001.

        [13] 楊興強(qiáng),劉翔鵬,劉毅.Linux進(jìn)程狀態(tài)演化過(guò)程的圖形學(xué)表示[J].系統(tǒng)仿真學(xué)報(bào),2013,25(10):2444-2448.

        [14] 龍飛.嵌入式Linux系統(tǒng)內(nèi)核實(shí)時(shí)性研究[D].沈陽(yáng):沈陽(yáng)工業(yè)大學(xué),2012.

        [15] 奚琪,曾勇軍,王清賢,等.一種動(dòng)靜結(jié)合的代碼反匯編框架[J].小型微型計(jì)算機(jī)系統(tǒng),2013(10):2251-2255.

        [16] 黃奉孝,高艷華,張學(xué)軍.基于嵌入式構(gòu)件的編程語(yǔ)言融合技術(shù)研究[J].計(jì)算機(jī)工程與設(shè)計(jì),2012,33(11):4138-4141.

        RESEARCHONARM-BASEDLINUXDRIVERDEBUGGINGTECHNOLOGY

        GongChenCaiWen

        (School of Information,Mechanical and Electrical Engineering,Shanghai Normal University,Shanghai 200234,China)

        WhenperformingLinuxdrivertransplantationonARM,itisneededtomodify,deleteoraddLinuxkernelcodes,butwhichmayresultinmanyunexpectederrorsatruntime.Atthistimetodebugcodessoastofindthecauseandpositionoftheerrorarenecessary.Forthisrequirement,weproposeandimplementtwonewdebuggingtechniques.Thefirstoneistoconstructaprintingfunctiontostoreadditionalprintinformationinabufferseparately,andtooutputitwiththehelpofprocfilesystem.Itachievestheseparationbetweentheadditionalprintinformationandtheprintinformationofthekernelitself,andmakesthesearchmoreconvenient.Thesecondoneistodeterminethepositionofsystemdeadbymakinguseoftheunceasingcharacteristicofsystemclockinterrupt.Itisshownthroughexperimentthatthistechniquefindsthepositionofendlessloopquickly,andsavesalargeamountofcodesearchandanalysiswork.

        LinuxDebugProcfilesystemSystemclockinterrupt

        2014-08-26。鞏琛,碩士生,主研領(lǐng)域:嵌入式系統(tǒng)與通信控制系統(tǒng)。蔡文,副教授。

        TP314

        ADOI:10.3969/j.issn.1000-386x.2016.03.054

        猜你喜歡
        進(jìn)程調(diào)試
        債券市場(chǎng)對(duì)外開放的進(jìn)程與展望
        基于航拍無(wú)人機(jī)的設(shè)計(jì)與調(diào)試
        電子制作(2018年12期)2018-08-01 00:47:44
        核電廠主給水系統(tǒng)調(diào)試
        無(wú)線通信中頻線路窄帶臨界調(diào)試法及其應(yīng)用
        電子制作(2017年19期)2017-02-02 07:08:38
        調(diào)壓柜的調(diào)試與試運(yùn)行探討
        工業(yè)電氣設(shè)備控制系統(tǒng)的安裝與調(diào)試
        音頻處理器的調(diào)試
        我國(guó)高等教育改革進(jìn)程與反思
        Linux僵死進(jìn)程的產(chǎn)生與避免
        男女平等進(jìn)程中出現(xiàn)的新矛盾和新問(wèn)題
        亚洲国际无码中文字幕| 国产精品内射久久一级二| 无码人妻一区二区三区兔费| 国产精品久久久久电影网| 亚洲嫩草影院久久精品| 亚洲精品国产av成人网| 亚洲国产亚综合在线区| 欧美国产一区二区三区激情无套| 美女一级毛片免费观看97| 国产免费一区二区三区三| 可以免费看亚洲av的网站| 久久夜色精品国产欧美乱| 国产极品美女高潮抽搐免费网站 | 婷婷五月综合丁香在线| 国产成人亚洲精品77| 老司机在线免费视频亚洲| 午夜熟女插插xx免费视频| 搡老熟女老女人一区二区| 久久这里有精品国产电影网| 中文字幕av素人专区| 国产美女做爰免费视频| 亚洲精品国产美女久久久| 国产精品综合色区av| 中文乱码字幕精品高清国产| 无码日韩精品一区二区三区免费| 国产精品久久1024| 亚洲女人天堂成人av在线| 欧美激情综合色综合啪啪五月| 无码人妻品一区二区三区精99| 国产自产拍精品视频免费看| 亚洲综合在线观看一区二区三区| 亚洲精品国产美女久久久| 久久99国产伦精品免费| 青青草视频在线观看9| 亚洲精品无码专区在线在线播放| 老少交欧美另类| 东风日产系列全部车型| 女色av少妇一区二区三区| a级毛片免费观看网站| 在线亚洲AV不卡一区二区| 男女射精视频在线观看网站|