




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、1第第4 章章 調(diào)試技術(shù)調(diào)試技術(shù)內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持 通過打印調(diào)試通過打印調(diào)試 通過查詢調(diào)試通過查詢調(diào)試 通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試 調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障 調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具2內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持l內(nèi)核開發(fā)者建立了許多用于支持調(diào)試的功能,以方便調(diào)試,內(nèi)核開發(fā)者建立了許多用于支持調(diào)試的功能,以方便調(diào)試,但這些功能會導(dǎo)致性能下降,發(fā)行版自帶內(nèi)核中往往關(guān)閉了但這些功能會導(dǎo)致性能下降,發(fā)行版自帶內(nèi)核中往往關(guān)閉了這些功能這些功能l內(nèi)核開發(fā)者需要這些功能,應(yīng)該打開這些調(diào)試功能內(nèi)核開發(fā)者需要這些功能,應(yīng)該打開這些調(diào)試功能l重新配置、編譯、安裝內(nèi)核重新配置、編譯、安裝內(nèi)
2、核lKernel hacking菜單中有如下選項菜單中有如下選項CONFIG_DEBUG_KERNEL 調(diào)試選項總開關(guān),關(guān)時全關(guān),開時并不打開下級子開關(guān)調(diào)試選項總開關(guān),關(guān)時全關(guān),開時并不打開下級子開關(guān)CONFIG_DEBUG_SLAB 開啟內(nèi)存分配函數(shù)中的類型檢查,可以檢測內(nèi)存溢出及開啟內(nèi)存分配函數(shù)中的類型檢查,可以檢測內(nèi)存溢出及忘記初始化錯誤忘記初始化錯誤3內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持CONFIG_DEBUG_PAGEALLOC 該選項大降速度,但可定位特定內(nèi)存損壞錯誤所在位置該選項大降速度,但可定位特定內(nèi)存損壞錯誤所在位置CONFIG_DEBUG_SPINLOCK 內(nèi)核將捕獲未初始化自
3、旋鎖及兩次解開同一鎖等錯誤內(nèi)核將捕獲未初始化自旋鎖及兩次解開同一鎖等錯誤CONFIG_DEBUG_SPINLOCK_SLEEP 檢查擁有自旋鎖時的休眠企圖檢查擁有自旋鎖時的休眠企圖CONFIG_INIT_DEBUG 用于初始化完成后對用于初始化的內(nèi)存空間的訪問檢查用于初始化完成后對用于初始化的內(nèi)存空間的訪問檢查CONFIG_DEBUG_INFO 使內(nèi)核的構(gòu)造包含完整的調(diào)試信息,使內(nèi)核的構(gòu)造包含完整的調(diào)試信息,gdb需要需要4內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持CONFIG_MAGIC_SYSRQ 打開打開“SYsRq魔法魔法”按鍵按鍵CONFIG_DEBUG_STACKOVERFLOWCONFIG
4、_DEBUG_STACK_USAGE 幫助跟蹤內(nèi)核棧溢出問題,前者在內(nèi)核中增加明確有溢幫助跟蹤內(nèi)核棧溢出問題,前者在內(nèi)核中增加明確有溢出檢查,后者讓內(nèi)核監(jiān)視棧的使用,出檢查,后者讓內(nèi)核監(jiān)視棧的使用, 并通過并通過SYsRq按按鍵輸出一些統(tǒng)計信息鍵輸出一些統(tǒng)計信息lCONFIG_KALLSYMS出現(xiàn)在出現(xiàn)在General setup/Standard features菜單中菜單中內(nèi)核中包含用于調(diào)試上下文的符號信息內(nèi)核中包含用于調(diào)試上下文的符號信息5內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持lCONFIG_IKCONFIGlCONFIG_IKCONFIG_PROC出現(xiàn)在出現(xiàn)在General setup菜單中
5、菜單中讓完整的內(nèi)核配置狀態(tài)包含到內(nèi)核中,并可通過讓完整的內(nèi)核配置狀態(tài)包含到內(nèi)核中,并可通過/proc訪問訪問lCONFIG_ACPI_DEBUG出現(xiàn)在出現(xiàn)在Power management/ACPI菜單中菜單中打開打開ACPI(Advanced Configuration and Power Interface)中中的詳細(xì)調(diào)試信息,若疑遇到問題與的詳細(xì)調(diào)試信息,若疑遇到問題與ACPI相關(guān)時用相關(guān)時用lCONFIG_DEBUG_DRIVER出現(xiàn)在出現(xiàn)在Device drivers菜單中菜單中打開驅(qū)動程序核心中的調(diào)試信息,可以幫助跟蹤底層支持代碼中打開驅(qū)動程序核心中的調(diào)試信息,可以幫助跟蹤底層支持
6、代碼中的問題的問題6內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持lCONFIG_SCSI_CONSTANTS出現(xiàn)在出現(xiàn)在Device drivers/SCSI device support菜單中菜單中打開詳細(xì)的打開詳細(xì)的SCSI錯誤消息,開發(fā)錯誤消息,開發(fā)SCSI驅(qū)動時可用驅(qū)動時可用lCONFIG_INPUT_EVBUG出現(xiàn)在出現(xiàn)在Device drivers/Input device support菜單中菜單中打開對輸入事件的詳細(xì)記錄,開發(fā)輸入設(shè)備驅(qū)動時可用打開對輸入事件的詳細(xì)記錄,開發(fā)輸入設(shè)備驅(qū)動時可用lCONFIG_PROFILING出現(xiàn)在出現(xiàn)在Profiling support菜單中菜單中用于系統(tǒng)
7、性能的調(diào)節(jié),但對跟蹤內(nèi)核掛起及相關(guān)問題也有幫助用于系統(tǒng)性能的調(diào)節(jié),但對跟蹤內(nèi)核掛起及相關(guān)問題也有幫助7第第4 章章 調(diào)試技術(shù)調(diào)試技術(shù)內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持 通過打印調(diào)試通過打印調(diào)試 通過查詢調(diào)試通過查詢調(diào)試 通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試 調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障 調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具8通過打印調(diào)試通過打印調(diào)試lPrintk是內(nèi)核調(diào)試中最簡單有效的工具,通過在內(nèi)核是內(nèi)核調(diào)試中最簡單有效的工具,通過在內(nèi)核代碼的某些關(guān)鍵地方放置一條代碼的某些關(guān)鍵地方放置一條printk語句,打印一些語句,打印一些信息,即可知道運(yùn)行代碼的某些行為,例:信息,即可知道運(yùn)行代碼的某些行為,例: prin
8、tk(KERN_CRIT Im trashed; giving up on %pn, ptr);lPrintk的使用需要包含頭文件的使用需要包含頭文件l只有在消息優(yōu)先級高于控制臺優(yōu)先級時,信息才能出只有在消息優(yōu)先級高于控制臺優(yōu)先級時,信息才能出現(xiàn)在終端上現(xiàn)在終端上l控制臺日志級別控制臺日志級別console_loglevel的初始值為的初始值為DEFAULT_CONSOLE_LOGLEVE,可通過可通過sys_syslog系統(tǒng)調(diào)用修改,也可通過文本文件系統(tǒng)調(diào)用修改,也可通過文本文件/proc/sys/kernel/printk修改修改9通過打印調(diào)試通過打印調(diào)試l例例 如下指令將控制臺日志級別修
9、改為如下指令將控制臺日志級別修改為8 # echo 8 /proc/sys/kernel/printkl下表為消息日志級別,數(shù)字越小,優(yōu)先級越高下表為消息日志級別,數(shù)字越小,優(yōu)先級越高 日志級別日志級別 描述描述 KERN_EMERG 緊急事件消息緊急事件消息 KERN_ALERT 用于需要立即采取動作的情況用于需要立即采取動作的情況 KERN_CRIT 臨界狀態(tài),通常涉及嚴(yán)重的硬件或軟件操作失敗臨界狀態(tài),通常涉及嚴(yán)重的硬件或軟件操作失敗 KERN_ERR 用于報告錯誤狀態(tài)用于報告錯誤狀態(tài) KERN_WARNING 對可能出現(xiàn)問題的情況進(jìn)行警告對可能出現(xiàn)問題的情況進(jìn)行警告 KERN_NOTIC
10、E 有必要進(jìn)行提示的情形有必要進(jìn)行提示的情形 KERN_INFO 提示性信息提示性信息 KERN_DEBUG 用于調(diào)試信息用于調(diào)試信息10通過打印調(diào)試通過打印調(diào)試l未指定消息優(yōu)先級的未指定消息優(yōu)先級的 printk 語句缺省優(yōu)先級是語句缺省優(yōu)先級是 DEFAULT_MESSAGE_LOGLEVEL, 在在 kernel/printk.c 里指定作為一個整數(shù)里指定作為一個整數(shù). 在在 2.6.10 內(nèi)核內(nèi)核中中, 為為 KERN_WARNING。11通過打印調(diào)試通過打印調(diào)試l消息如何被記錄消息如何被記錄printk將消息寫到一個長度為將消息寫到一個長度為_LOG_BUF_LEN(4KB1MB,默
11、認(rèn),默認(rèn)16KB)的循環(huán)緩沖區(qū)的循環(huán)緩沖區(qū)中中,然后喚醒在該緩沖區(qū)上等待消息的進(jìn)程然后喚醒在該緩沖區(qū)上等待消息的進(jìn)程 睡眠在睡眠在syslog系統(tǒng)調(diào)用上的進(jìn)程系統(tǒng)調(diào)用上的進(jìn)程(調(diào)用調(diào)用syslog()-寫、寫、openlog()-打打開或開或closelog()-關(guān)閉的進(jìn)程關(guān)閉的進(jìn)程) 正在讀取文件正在讀取文件/proc/kmsg的進(jìn)程的進(jìn)程用戶空間守護(hù)進(jìn)程用戶空間守護(hù)進(jìn)程klogd運(yùn)行時讀取內(nèi)核消息(通過運(yùn)行時讀取內(nèi)核消息(通過syslog系統(tǒng)調(diào)用或系統(tǒng)調(diào)用或/proc/dmsg文件,默認(rèn)為后者),并傳文件,默認(rèn)為后者),并傳給另一個守護(hù)進(jìn)程給另一個守護(hù)進(jìn)程syslogdsyslogd根據(jù)根
12、據(jù)/etc/syslog.conf設(shè)置的處理方法處理收到的設(shè)置的處理方法處理收到的消息,默認(rèn)追加到消息,默認(rèn)追加到/var/log/message中中klogd也可將消息存入一指定文件中,不給也可將消息存入一指定文件中,不給syslogd12通過打印調(diào)試通過打印調(diào)試l若若klogd沒運(yùn)行,消息不會送到用戶空間,只能查看沒運(yùn)行,消息不會送到用戶空間,只能查看/proc/kmsg文件(可通過文件(可通過dmesg命令)命令)13通過打印調(diào)試通過打印調(diào)試l開啟及關(guān)閉消息開啟及關(guān)閉消息printk對調(diào)試和測試新代碼很有幫助,但在正式發(fā)布驅(qū)動對調(diào)試和測試新代碼很有幫助,但在正式發(fā)布驅(qū)動程序時,就需要刪除
13、或禁用程序時,就需要刪除或禁用如何有效地啟用如何有效地啟用/禁用它們?禁用它們?#undef PDEBUG #ifdef SCULL_DEBUG# ifdef _KERNEL_# define PDEBUG(fmt, args.) printk( KERN_DEBUG scull: fmt, # args)# else # define PDEBUG(fmt, args.) fprintf(stderr, fmt, # args)# endif#else# define PDEBUG(fmt, args.) #endif#undef PDEBUGG#define PDEBUGG(fmt, ar
14、gs.)14通過打印調(diào)試通過打印調(diào)試l打印速度控制打印速度控制Printk有時每秒鐘能產(chǎn)生上萬條消息充滿控制臺或使有時每秒鐘能產(chǎn)生上萬條消息充滿控制臺或使日志文件溢出,若控制臺為串口超級終端,過高的消日志文件溢出,若控制臺為串口超級終端,過高的消息輸出速度會使系統(tǒng)變慢,甚至無法正常響應(yīng)。息輸出速度會使系統(tǒng)變慢,甚至無法正常響應(yīng)。內(nèi)核提供了控制打印速度的函數(shù),原型為:內(nèi)核提供了控制打印速度的函數(shù),原型為: int printk_ratelimit(void);可通過函數(shù)的返回值來控制打印輸出,若函數(shù)返回一可通過函數(shù)的返回值來控制打印輸出,若函數(shù)返回一個非零值,繼續(xù)輸出消息,否則跳過,例:個非零值
15、,繼續(xù)輸出消息,否則跳過,例: if (printk_ratelimit( ) printk(KERN_NOTICE The printer is still on firen);15通過打印調(diào)試通過打印調(diào)試printk_ratelimit跟蹤發(fā)送到控制臺的消息數(shù)量,若超跟蹤發(fā)送到控制臺的消息數(shù)量,若超過某一閾值,則返回過某一閾值,則返回0,否則非,否則非0可通過修改下列文件控制可通過修改下列文件控制printk_ratelimit的行為的行為 /proc/sys/kernel/printk_ratelimit /proc/sys/kernel/printk_ratelimit_burst16
16、通過打印調(diào)試通過打印調(diào)試l打印設(shè)備編號打印設(shè)備編號當(dāng)從一個驅(qū)動程序打印消息時,有時會希望打印關(guān)聯(lián)當(dāng)從一個驅(qū)動程序打印消息時,有時會希望打印關(guān)聯(lián)的設(shè)備編號,內(nèi)核提供了兩個宏:的設(shè)備編號,內(nèi)核提供了兩個宏:int print_dev_t(char *buffer, dev_t dev);char *format_dev_t(char *buffer, dev_t dev);17第第4 章章 調(diào)試技術(shù)調(diào)試技術(shù)內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持 通過打印調(diào)試通過打印調(diào)試 通過查詢調(diào)試通過查詢調(diào)試 通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試 調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障 調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具18通過查詢調(diào)試通過查詢
17、調(diào)試l通過打印調(diào)試的缺點(diǎn)通過打印調(diào)試的缺點(diǎn)syslogd會一直保持對其輸出文件的同步刷新,降低性會一直保持對其輸出文件的同步刷新,降低性能。雖可通過在能。雖可通過在/etc/syslog.conf中日志文件的名字前中日志文件的名字前加一減號前綴來避免,但調(diào)試完后配置會被保留下來加一減號前綴來避免,但調(diào)試完后配置會被保留下來雖可通過降低雖可通過降低console_loglevel來減少控制臺輸出,但來減少控制臺輸出,但大量大量printk的使用也降低性能的使用也降低性能l大多數(shù)情況下,獲取相關(guān)信息的最好方法是在需要的大多數(shù)情況下,獲取相關(guān)信息的最好方法是在需要的時候才去查詢,而不是持續(xù)不斷地產(chǎn)生
18、數(shù)據(jù),如時候才去查詢,而不是持續(xù)不斷地產(chǎn)生數(shù)據(jù),如ps、netstat、vmstat等等l驅(qū)動程序開發(fā)中可用的查詢方法有驅(qū)動程序開發(fā)中可用的查詢方法有在在/proc中創(chuàng)建文件、中創(chuàng)建文件、ioctl方法、方法、sysfs等等19通過查詢調(diào)試通過查詢調(diào)試1. /proc文件系統(tǒng)文件系統(tǒng)/proc文件系統(tǒng)是一種讀時創(chuàng)建的文件系統(tǒng)是一種讀時創(chuàng)建的“內(nèi)存文件系統(tǒng)內(nèi)存文件系統(tǒng)”。每個文件都綁定一個內(nèi)核函數(shù),當(dāng)文件被讀取時,該每個文件都綁定一個內(nèi)核函數(shù),當(dāng)文件被讀取時,該函數(shù)動態(tài)地生成文件的函數(shù)動態(tài)地生成文件的“內(nèi)容內(nèi)容”內(nèi)核使用內(nèi)核使用/proc文件系統(tǒng)向外界導(dǎo)出信息,如文件系統(tǒng)向外界導(dǎo)出信息,如/pr
19、oc/modules因此可通過因此可通過/proc文件系統(tǒng)將設(shè)備信息導(dǎo)出到用戶空間文件系統(tǒng)將設(shè)備信息導(dǎo)出到用戶空間,以方便對設(shè)備驅(qū)動程序進(jìn)行調(diào)試,以方便對設(shè)備驅(qū)動程序進(jìn)行調(diào)試l在在/proc中實(shí)現(xiàn)文件系統(tǒng)需做兩件事中實(shí)現(xiàn)文件系統(tǒng)需做兩件事創(chuàng)建一個函數(shù),用于在文件被讀取時生成文件數(shù)據(jù)創(chuàng)建一個函數(shù),用于在文件被讀取時生成文件數(shù)據(jù)創(chuàng)建文件節(jié)點(diǎn)創(chuàng)建文件節(jié)點(diǎn)20通過查詢調(diào)試通過查詢調(diào)試l創(chuàng)建函數(shù)創(chuàng)建函數(shù)當(dāng)一個進(jìn)程讀取當(dāng)一個進(jìn)程讀取 /proc 文件時文件時, 內(nèi)核會分配一頁內(nèi)存,內(nèi)核會分配一頁內(nèi)存,我們可以把設(shè)備數(shù)據(jù)寫入其中,以返回給用戶空間。我們可以把設(shè)備數(shù)據(jù)寫入其中,以返回給用戶空間。 那個將數(shù)據(jù)寫
20、入這個緩存區(qū)的函數(shù)那個將數(shù)據(jù)寫入這個緩存區(qū)的函數(shù), 就是我們要創(chuàng)建的就是我們要創(chuàng)建的函數(shù),稱為函數(shù),稱為 read_proc 方法,函數(shù)原型如下:方法,函數(shù)原型如下:int (*read_proc)(char *page, char *start, off_t offset, int count, int *eof, void *data); page:指向用來寫入數(shù)據(jù)的緩沖區(qū),大小為一頁指向用來寫入數(shù)據(jù)的緩沖區(qū),大小為一頁 start:指向數(shù)據(jù)寫入頁中的具體位置指向數(shù)據(jù)寫入頁中的具體位置 offset:相對于頁邊界的偏移量相對于頁邊界的偏移量 count:寫入的字節(jié)數(shù)寫入的字節(jié)數(shù) eof:指
21、向一個整型數(shù)的指針,可返回一個整型數(shù)指向一個整型數(shù)的指針,可返回一個整型數(shù) data:提供給驅(qū)動程序的專用數(shù)據(jù)指針:提供給驅(qū)動程序的專用數(shù)據(jù)指針21通過查詢調(diào)試通過查詢調(diào)試scull中的實(shí)現(xiàn)中的實(shí)現(xiàn)int scull_read_procmem(char *buf, char *start, off_t offset, int count, int *eof, void *data) int i, j, len = 0; int limit = count - 80; for (i = 0; i scull_nr_devs & len data; if (down_interruptib
22、le(&d-sem) return -ERESTARTSYS; len += sprintf(buf+len,nDevice %i: qset %i, q %i, sz %lin, i, d-qset, d-quantum, d-size); for (; qs & len next) len += sprintf(buf + len, item at %p, qset at %pn, qs, qs-data); if (qs-data & !qs-next) for (j = 0; j qset; j+) if (qs-dataj) len += sprintf(bu
23、f + len, % 4i: %8pn, j, qs-dataj); up(&scull_devicesi.sem); *eof = 1; return len;22通過查詢調(diào)試通過查詢調(diào)試l創(chuàng)建創(chuàng)建/proc文件節(jié)點(diǎn)文件節(jié)點(diǎn)原型原型struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void *data); name:要創(chuàng)建的文件名要創(chuàng)建的文件名 mode:該文件的保護(hù)掩碼,該文
24、件的保護(hù)掩碼,0為系統(tǒng)默認(rèn)值(全局可讀)為系統(tǒng)默認(rèn)值(全局可讀) base:指定該文件所在的目錄,若為:指定該文件所在的目錄,若為NULL,則在,則在/proc的根目錄的根目錄 read_proc:實(shí)現(xiàn)該文件的:實(shí)現(xiàn)該文件的read_proc方法方法Scull中的實(shí)現(xiàn)中的實(shí)現(xiàn)create_proc_read_entry(scullmem, 0 , NULL ,scull_read_procmem,NULL );節(jié)點(diǎn)刪除節(jié)點(diǎn)刪除remove_proc_entry(scullmem, NULL /* parent dir */);23通過查詢調(diào)試通過查詢調(diào)試2. seq_file接口接口在在/pr
25、oc中創(chuàng)建文件的另一種方式。在中創(chuàng)建文件的另一種方式。在/proc下創(chuàng)建的下創(chuàng)建的文件大小通常不超過一頁,文件大小通常不超過一頁,seq_file接口不受此限制接口不受此限制,且相當(dāng)靈活。,且相當(dāng)靈活。seq_file接口假定我們正在創(chuàng)建的虛擬文件要順序遍接口假定我們正在創(chuàng)建的虛擬文件要順序遍歷一個項目序列,而這些項目正是必須要返回給用戶歷一個項目序列,而這些項目正是必須要返回給用戶空間的空間的為使用為使用seq_file,我們必須創(chuàng)建一個簡單的,我們必須創(chuàng)建一個簡單的“迭代器迭代器(iterator)”對象,該對象用來表示項目系列中的位對象,該對象用來表示項目系列中的位置,每前進(jìn)一步,該對象
26、輸出序列中的一個項目置,每前進(jìn)一步,該對象輸出序列中的一個項目迭代器對象分別為迭代器對象分別為start、next、stop和和show24通過查詢調(diào)試通過查詢調(diào)試Start方法首先被調(diào)用方法首先被調(diào)用,原型如下:原型如下:void *start(struct seq_file *sfile, loff_t *pos); sfile通常被忽略通常被忽略 pos表示讀取位置,為指向下一個項目的指針。表示讀取位置,為指向下一個項目的指針。scull 驅(qū)驅(qū)動將每個設(shè)備作為系列中的一項動將每個設(shè)備作為系列中的一項, 因此因此pos 可作為可作為 scull_device 數(shù)組的索引。于是數(shù)組的索引。于
27、是, scull 使用的使用的 start 方方法如下:法如下: static void *scull_seq_start(struct seq_file *s, loff_t *pos) if (*pos = scull_nr_devs) return NULL; return scull_devices + *pos;25通過查詢調(diào)試通過查詢調(diào)試next 函數(shù)應(yīng)當(dāng)將函數(shù)應(yīng)當(dāng)將iterator移動到下一個位置移動到下一個位置, 如果序如果序列里什么都沒有剩下就返回列里什么都沒有剩下就返回 NULL,這個方法的原,這個方法的原型是型是:void *next(struct seq_file *s
28、file, void *v, loff_t *pos); v 是先前對是先前對 start 或者或者 next 調(diào)用所返回的調(diào)用所返回的 iterator, pos 是文件的當(dāng)前位置。是文件的當(dāng)前位置。next 應(yīng)當(dāng)遞增應(yīng)當(dāng)遞增 pos 指向的值,指向的值, scull 的的next方法實(shí)現(xiàn)如下方法實(shí)現(xiàn)如下: static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos) (*pos)+; if (*pos = scull_nr_devs) return NULL; return scull_devices + *po
29、s;26通過查詢調(diào)試通過查詢調(diào)試當(dāng)內(nèi)核處理完當(dāng)內(nèi)核處理完 iterator之后之后, 會調(diào)用會調(diào)用 stop方法通知我們方法通知我們進(jìn)行清除工作,進(jìn)行清除工作,stop函數(shù)原型如下:函數(shù)原型如下:void stop(struct seq_file *sfile, void *v); scull 實(shí)現(xiàn)沒有清理工作要做實(shí)現(xiàn)沒有清理工作要做, 所以它的所以它的 stop 方法是空方法是空的的.在上述調(diào)用之間在上述調(diào)用之間, 內(nèi)核會調(diào)用內(nèi)核會調(diào)用 show 方法來將實(shí)際數(shù)據(jù)方法來將實(shí)際數(shù)據(jù)輸出到用戶空間輸出到用戶空間. 這個方法的原型是這個方法的原型是:int show(struct seq_file
30、 *sfile, void *v); 這個方法為這個方法為 iterator v 指向的項目建立輸出。但是,它指向的項目建立輸出。但是,它不能使用不能使用 printk, 應(yīng)該使用針對應(yīng)該使用針對seq_file的一套特殊函數(shù)的一套特殊函數(shù)27通過查詢調(diào)試通過查詢調(diào)試int seq_printf(struct seq_file *sfile, const char *fmt, .);這是這是 seq_file 實(shí)現(xiàn)的實(shí)現(xiàn)的 printf等價等價 函數(shù)函數(shù); 它采用常用的它采用常用的格式串和附加值參數(shù)格式串和附加值參數(shù). 你必須將給你必須將給 show 函數(shù)的函數(shù)的 set_file 結(jié)構(gòu)傳遞給
31、它結(jié)構(gòu)傳遞給它Scull中的中的show方法實(shí)現(xiàn)如下:方法實(shí)現(xiàn)如下:28通過查詢調(diào)試通過查詢調(diào)試static int scull_seq_show(struct seq_file *s, void *v) struct scull_dev *dev = (struct scull_dev *) v; struct scull_qset *d; int i; if (down_interruptible(&dev-sem) return -ERESTARTSYS; seq_printf(s, nDevice %i: qset %i, q %i, sz %lin, (int) (dev -
32、 scull_devices), dev-qset, dev-quantum, dev-size); for (d = dev-data; d; d = d-next) seq_printf(s, item at %p, qset at %pn, d, d-data); if (d-data & !d-next) for (i = 0; i qset; i+) if (d-datai) seq_printf(s, % 4i: %8pn, i, d-datai); up(&dev-sem); return 0;29通過查詢調(diào)試通過查詢調(diào)試l上面已經(jīng)定義了完整的迭代器操作函數(shù),上面
33、已經(jīng)定義了完整的迭代器操作函數(shù),scull必須必須將這些函數(shù)打包并和將這些函數(shù)打包并和/proc中的某個文件連接起來,中的某個文件連接起來,首先要填沖一個首先要填沖一個seq_operations結(jié)構(gòu)體:結(jié)構(gòu)體:static struct seq_operations scull_seq_ops = .start = scull_seq_start, .next = scull_seq_next, .stop = scull_seq_stop, .show = scull_seq_show;30通過查詢調(diào)試通過查詢調(diào)試l首先創(chuàng)建文件的首先創(chuàng)建文件的open方法,該方法將文件連接到方法,該方法將
34、文件連接到seq_file操作操作static int scull_proc_open(struct inode *inode, struct file *fil return seq_open(file, &scull_seq_ops);31通過查詢調(diào)試通過查詢調(diào)試l對對seq_open的調(diào)用將的調(diào)用將file結(jié)構(gòu)和我們上面定義的序結(jié)構(gòu)和我們上面定義的序列操作連接在一起。事實(shí)上列操作連接在一起。事實(shí)上, open 是我們必須自己是我們必須自己實(shí)現(xiàn)的唯一文件操作實(shí)現(xiàn)的唯一文件操作, 因此我們現(xiàn)在可以建立我們的因此我們現(xiàn)在可以建立我們的 file_operations 結(jié)構(gòu)結(jié)構(gòu):stat
35、ic struct file_operations scull_proc_ops = .owner = THIS_MODULE, .open = scull_proc_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release;32通過查詢調(diào)試通過查詢調(diào)試l建立建立/proc 文件節(jié)點(diǎn)文件節(jié)點(diǎn)函數(shù)原型函數(shù)原型struct proc_dir_entry *create_proc_entry(const char *name,mode_t mode, struct proc_dir_entry *parent); name
36、:要創(chuàng)建的文件名:要創(chuàng)建的文件名 mode:該文件的保護(hù)掩碼:該文件的保護(hù)掩碼 parent:父目錄:父目錄Scull中的實(shí)現(xiàn)中的實(shí)現(xiàn)entry = create_proc_entry(scullseq, 0, NULL);if (entry) entry-proc_fops = &scull_proc_ops;33通過查詢調(diào)試通過查詢調(diào)試lioctl是一個作用于文件描述符上的系統(tǒng)調(diào)用是一個作用于文件描述符上的系統(tǒng)調(diào)用, 它接收它接收一個命令號以及一個命令號以及(可選地可選地)另一個參數(shù)另一個參數(shù), 常常是一個指常常是一個指針。針。 作為作為/proc 文件系統(tǒng)的替代文件系統(tǒng)的替代,
37、你可以實(shí)現(xiàn)幾個用你可以實(shí)現(xiàn)幾個用來調(diào)試用的來調(diào)試用的 ioctl 命令,以從驅(qū)動程序拷貝相關(guān)的數(shù)命令,以從驅(qū)動程序拷貝相關(guān)的數(shù)據(jù)到用戶空間據(jù)到用戶空間, 在這里你可以檢查它們。在這里你可以檢查它們。34第第4 章章 調(diào)試技術(shù)調(diào)試技術(shù)內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持 通過打印調(diào)試通過打印調(diào)試 通過查詢調(diào)試通過查詢調(diào)試 通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試 調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障 調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具35通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試l通過監(jiān)視用戶空間中應(yīng)用程序的運(yùn)行情況,可以捕捉到一些通過監(jiān)視用戶空間中應(yīng)用程序的運(yùn)行情況,可以捕捉到一些問題。有幾個方法可以用來監(jiān)視用戶空間程序運(yùn)行,問題。有幾個方法可
38、以用來監(jiān)視用戶空間程序運(yùn)行, 你可以你可以運(yùn)行一個調(diào)試器來單步跟蹤它的函數(shù)運(yùn)行一個調(diào)試器來單步跟蹤它的函數(shù), 插入打印語句或者在插入打印語句或者在 strace 下運(yùn)行程序等等。本節(jié)主要討論下運(yùn)行程序等等。本節(jié)主要討論strace技術(shù)。技術(shù)。lstrace命令功能強(qiáng),可以顯示由用戶空間程序所發(fā)出的所有命令功能強(qiáng),可以顯示由用戶空間程序所發(fā)出的所有系統(tǒng)調(diào)用,包括調(diào)用參數(shù)及用符號表示的返回值系統(tǒng)調(diào)用,包括調(diào)用參數(shù)及用符號表示的返回值lstrace 有很多命令行選項:有很多命令行選項:-t :顯示每個調(diào)用發(fā)生的時間:顯示每個調(diào)用發(fā)生的時間-T:顯示調(diào)用所花費(fèi)的時間:顯示調(diào)用所花費(fèi)的時間 -e:限定被
39、跟蹤的調(diào)用類型:限定被跟蹤的調(diào)用類型-o:重定向輸出到一個文件中,:重定向輸出到一個文件中, 缺省情況下輸出到缺省情況下輸出到 stderr.lstrace 從內(nèi)核獲取信息,這意味著它可以跟蹤一個不帶有調(diào)從內(nèi)核獲取信息,這意味著它可以跟蹤一個不帶有調(diào)試支持試支持 (對對 gcc是是 -g 選項選項)以及去掉了符號信息的程序。以及去掉了符號信息的程序。36通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試l例例 strace ls /dev /dev/scull0open(/dev, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 3fstat64(3, st_mode=S_
40、IFDIR|0755, st_size=24576, .) = 0fcntl64(3, F_SETFD, FD_CLOEXEC) = 0getdents64(3, /* 141 entries */, 4096) = 4088.getdents64(3, /* 0 entries */, 4096) = 0close(3) = 0.fstat64(1, st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), .) = 0write(1, MAKEDEVnadmmidi0nadmmidi1nadmmid., 4096) = 4000write(1, bnpt
41、ywcnptywdnptywenptywfnptyx0n., 96) = 96write(1, bnptyxcnptyxdnptyxenptyxfnptyy0n., 4096) = 3904write(1, s17nvcs18nvcs19nvcs2nvcs20nvcs21., 192) = 192write(1, nvcs47nvcs48nvcs49nvcs5nvcs50nvc., 673) = 673close(1) = 0exit_group(0) = ?37通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試l例例 用用wc命令讀命令讀scull設(shè)備設(shè)備.open(/dev/scull0, O_RDONLY|O_L
42、ARGEFILE) = 3fstat64(3, st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), .) = 0read(3, MAKEDEVnadmmidi0nadmmidi1nadmmid., 16384) = 4000read(3, bnptywcnptywdnptywenptywfnptyx0n., 16384) = 4000read(3, s17nvcs18nvcs19nvcs2nvcs20nvcs21., 16384) = 865read(3, , 16384) = 0fstat64(1, st_mode=S_IFCHR|0620, st_
43、rdev=makedev(136, 1), .) = 0write(1, 8865 /dev/scull0n, 17) = 17close(3) = 0exit_group(0) = ?38第第4 章章 調(diào)試技術(shù)調(diào)試技術(shù)內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持 通過打印調(diào)試通過打印調(diào)試 通過查詢調(diào)試通過查詢調(diào)試 通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試 調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障 調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具39調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障1. oops消息消息oops是內(nèi)核發(fā)生錯誤時(比如引用了一個空指針)所是內(nèi)核發(fā)生錯誤時(比如引用了一個空指針)所展現(xiàn)給我們的一系列信息,這些信息包含了當(dāng)時展現(xiàn)給我們的一系列信息,這
44、些信息包含了當(dāng)時CPU的狀態(tài)、進(jìn)程的狀態(tài)、內(nèi)核堆棧的狀態(tài)以及調(diào)用棧的的狀態(tài)、進(jìn)程的狀態(tài)、內(nèi)核堆棧的狀態(tài)以及調(diào)用棧的記錄等記錄等大部分系統(tǒng)故障都是引用大部分系統(tǒng)故障都是引用 NULL 指針或者使用其他不指針或者使用其他不正確指針值引起的,這類故障通常會導(dǎo)致一個正確指針值引起的,這類故障通常會導(dǎo)致一個 oops 消息消息.40調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障l例例 faulty模塊中的模塊中的write調(diào)用由于引用空指針導(dǎo)致的調(diào)用由于引用空指針導(dǎo)致的oopsssize_t faulty_write (struct file *filp, const char _user *buf, size_t coun
45、t, loff_t *pos) *(int *)0 = 0; /*make a simple fault by dereferencing a NULL pointer */ return 0;41調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障Unable to handle kernel NULL pointer dereference at virtual address 00000000 printing eip:d083a064Oops: 0002 #1SMPCPU: 0EIP: 0060: Not taintedEFLAGS: 00010246 (2.6.6)EIP is at faulty_write+
46、0 x4/0 x10 faultyeax: 00000000 ebx: 00000000 ecx: 00000000 edx: 00000000esi: cf8b2460 edi: cf8b2480 ebp: 00000005 esp: c31c5f74ds: 007b es: 007b ss: 0068Process bash (pid: 2086, threadinfo=c31c4000 task=cfa0a6c0)Stack: c0150558 cf8b2460 080e9408 00000005 cf8b2480 00000000 cf8b2460 cf8b2460 fffffff7
47、080e9408 c31c4000 c0150682 cf8b2460 080e9408 00000005 cf8b2480 00000000 00000001 00000005 c0103f8f 00000001 080e9408 00000005 00000005Call Trace: vfs_write+0 xb8/0 x130 sys_write+0 x42/0 x70 syscall_call+0 x7/0 xbCode: 89 15 00 00 00 00 c3 90 8d 74 26 00 83 ec 0c b8 00 a6 83 d0說明引發(fā)內(nèi)核錯誤的原因說明內(nèi)核錯誤的事發(fā)現(xiàn)場
48、說明錯誤發(fā)生時函數(shù)調(diào)用鏈42調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障l例例 faulty模塊中的模塊中的read 調(diào)用由于緩沖區(qū)溢出引發(fā)的調(diào)用由于緩沖區(qū)溢出引發(fā)的oopsssize_t faulty_read(struct file *filp, char _user *buf, size_t count, loff_t *pos) int ret; char stack_buf4; /* Lets try a buffer overflow */ memset(stack_buf, 0 xff, 20); if (count 4) count = 4; /* copy 4 bytes to the user
49、 */ ret = copy_to_user(buf, stack_buf, count); if (!ret) return count; return ret;43調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障EIP: 0010:Unable to handle kernel paging request at virtual address ffffffff printing eip:ffffffffOops: 0000 #5SMPCPU: 0EIP: 0060: Not taintedEFLAGS: 00010296 (2.6.6)EIP is at 0 xffffffffeax: 0000000c ebx
50、: ffffffff ecx: 00000000 edx: bfffda7cesi: cf434f00 edi: ffffffff ebp: 00002000 esp: c27fff78ds: 007b es: 007b ss: 0068Process head (pid: 2331, threadinfo=c27fe000 task=c3226150)Stack: ffffffff bfffda70 00002000 cf434f20 00000001 00000286 cf434f00 fffffff7 bfffda70 c27fe000 c0150612 cf434f00 bfffda7
51、0 00002000 cf434f20 00000000 00000003 00002000 c0103f8f 00000003 bfffda70 00002000 00002000 bfffda70Call Trace: sys_read+0 x42/0 x70 syscall_call+0 x7/0 xbCode: Bad EIP value.44調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障2. 系統(tǒng)掛起系統(tǒng)掛起內(nèi)核代碼中的大多數(shù)錯誤通常只會導(dǎo)致一個內(nèi)核代碼中的大多數(shù)錯誤通常只會導(dǎo)致一個oops消息,但有時消息,但有時也會將系統(tǒng)掛起,系統(tǒng)真掛起時不會再響應(yīng)任何動作,包括也會將系統(tǒng)掛起,系統(tǒng)真掛起時不會再響應(yīng)任
52、何動作,包括Ctrl-Alt-Del 組合鍵組合鍵但有時系統(tǒng)不是真的掛起,只是某種原因使鍵盤被鎖住,此時可但有時系統(tǒng)不是真的掛起,只是某種原因使鍵盤被鎖住,此時可用用“SySRq魔法鍵(魔法鍵(magic SysRq key)”工具進(jìn)行調(diào)試工具進(jìn)行調(diào)試“ SySRq魔法鍵魔法鍵” 在大部分體系上都可用。在在大部分體系上都可用。在 PC 上,可通過上,可通過Alt 和和SysRq 鍵組合來激活,在別的平臺上可使用其他特殊鍵鍵組合來激活,在別的平臺上可使用其他特殊鍵(詳見詳見 documentation/sysrq.txt)來激活來激活, 在串口控制臺上也可用在串口控制臺上也可用,由第三個鍵來決定
53、其動作中,由第三個鍵來決定其動作中: r :關(guān)閉鍵盤原始模式。用于當(dāng)某個崩潰的應(yīng)用程序:關(guān)閉鍵盤原始模式。用于當(dāng)某個崩潰的應(yīng)用程序( 例如例如 X 服務(wù)服務(wù)器器 )讓鍵盤處于一個奇怪狀態(tài)。讓鍵盤處于一個奇怪狀態(tài)。 k :調(diào)用:調(diào)用“安全注意鍵安全注意鍵”( SAK ) 功能功能. SAK 將殺掉在當(dāng)前控制臺將殺掉在當(dāng)前控制臺上的所有運(yùn)行的進(jìn)程上的所有運(yùn)行的進(jìn)程, 給你一個干凈的終端給你一個干凈的終端. S:對全部磁盤進(jìn)行緊急同步:對全部磁盤進(jìn)行緊急同步.45調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障 u:umount, 嘗試以只讀模式重新加載所有磁盤。嘗試以只讀模式重新加載所有磁盤。 這個操作常常在這個操作常常
54、在 s 之后馬上調(diào)用之后馬上調(diào)用, 它可以在系統(tǒng)處于嚴(yán)重故障時節(jié)省很多檢查文件它可以在系統(tǒng)處于嚴(yán)重故障時節(jié)省很多檢查文件系統(tǒng)的時間。系統(tǒng)的時間。 b:boot,立刻重啟系統(tǒng)。,立刻重啟系統(tǒng)。 確認(rèn)要先同步和重新加載磁盤。確認(rèn)要先同步和重新加載磁盤。 p :打印處理器寄存器消息。:打印處理器寄存器消息。 t: 打印當(dāng)前任務(wù)列表。打印當(dāng)前任務(wù)列表。 m :打印內(nèi)存信息。:打印內(nèi)存信息。魔法鍵魔法鍵SysRq 必須在內(nèi)核配置中顯式使能必須在內(nèi)核配置中顯式使能, 大部分的發(fā)布版沒有大部分的發(fā)布版沒有使能它使能它, 因?yàn)槊黠@的安全理由因?yàn)槊黠@的安全理由. 對于用來開發(fā)驅(qū)動的系統(tǒng)對于用來開發(fā)驅(qū)動的系統(tǒng),
55、使能魔使能魔法鍵法鍵SysRq是值得的。是值得的。魔法鍵魔法鍵 sysrq 能在運(yùn)行時關(guān)閉能在運(yùn)行時關(guān)閉, 使用如下命令使用如下命令:echo 0 /proc/sys/kernel/sysrq 46第第4 章章 調(diào)試技術(shù)調(diào)試技術(shù)內(nèi)核中的調(diào)試支持內(nèi)核中的調(diào)試支持 通過打印調(diào)試通過打印調(diào)試 通過查詢調(diào)試通過查詢調(diào)試 通過監(jiān)視調(diào)試通過監(jiān)視調(diào)試 調(diào)試系統(tǒng)故障調(diào)試系統(tǒng)故障 調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具47調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具lgdb調(diào)試內(nèi)核調(diào)試內(nèi)核gdb /usr/src/linux/vmlinux /proc/kcore Vmlinux:一參,指定待調(diào)試的文件為非壓縮內(nèi)核映像文件一參,
56、指定待調(diào)試的文件為非壓縮內(nèi)核映像文件 /proc/kcore:二參,指定內(nèi)核在內(nèi)存中的核心映像,對于一個運(yùn):二參,指定內(nèi)核在內(nèi)存中的核心映像,對于一個運(yùn)行的內(nèi)核,核心映像就是運(yùn)行時的內(nèi)核映像行的內(nèi)核,核心映像就是運(yùn)行時的內(nèi)核映像gdb可以打印結(jié)構(gòu)體中存放的信息、跟蹤一個指針、輸出一個變可以打印結(jié)構(gòu)體中存放的信息、跟蹤一個指針、輸出一個變量的值、反匯編一個函數(shù)等量的值、反匯編一個函數(shù)等 p jiffies disassemble function打印數(shù)據(jù)時,內(nèi)核仍在運(yùn)行,各種數(shù)據(jù)在不同時間可能會有不同打印數(shù)據(jù)時,內(nèi)核仍在運(yùn)行,各種數(shù)據(jù)在不同時間可能會有不同的值,但的值,但gdb將第一次讀取的數(shù)據(jù)
57、放在緩存中,第二次讀取時得將第一次讀取的數(shù)據(jù)放在緩存中,第二次讀取時得到的仍是原數(shù)據(jù)到的仍是原數(shù)據(jù)執(zhí)行命令執(zhí)行命令core-file /proc/kcore刷新緩沖區(qū)后再讀刷新緩沖區(qū)后再讀48調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具lgdb調(diào)試可加載模塊調(diào)試可加載模塊上面的命令只可調(diào)試內(nèi)核,但對于可加載模塊卻上面的命令只可調(diào)試內(nèi)核,但對于可加載模塊卻無能為力,因?yàn)榭杉虞d模塊并沒有隨無能為力,因?yàn)榭杉虞d模塊并沒有隨vmlinux傳遞傳遞給給gdb,所以,所以gdb 對它一無所知對它一無所知 可加載模塊是可加載模塊是 ELF 格式的可執(zhí)行映象格式的可執(zhí)行映象, 它們被分它們被分成幾個代碼段成幾個代碼段.
58、一個典型的模塊可能包含一打或更一個典型的模塊可能包含一打或更多段多段, 以下以下 3 個段與調(diào)試相關(guān)個段與調(diào)試相關(guān): .text:這個段包含了模塊的可執(zhí)行代碼:這個段包含了模塊的可執(zhí)行代碼. .bss /.data :這:這 2 個段包含了模塊的變量個段包含了模塊的變量. 未初始化的未初始化的變量在變量在 .bss 中中, 已初始化的在已初始化的在 .data 里里.要想使要想使 gdb 能夠處理可加載模塊,必須告訴它模能夠處理可加載模塊,必須告訴它模塊的段加載位置。塊的段加載位置。49調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具每個模塊在加載后都會在每個模塊在加載后都會在 /sys/module 目錄下
59、產(chǎn)生一目錄下產(chǎn)生一個對應(yīng)的目錄,在該目錄下又有一個個對應(yīng)的目錄,在該目錄下又有一個sections目錄,目錄,sections下有下有.text、.bss、.data三個文件,文件內(nèi)容三個文件,文件內(nèi)容就是就是3個段的基地址。個段的基地址。 例如例如, 在加載在加載 scull 模塊后模塊后, /sys/module/scull/sections 會包含一個名為會包含一個名為 .text 的的文件,文件的內(nèi)容就是代碼段的基地址文件,文件的內(nèi)容就是代碼段的基地址.通過通過sysfs文件獲取模塊的段地址后,就可以使用如下文件獲取模塊的段地址后,就可以使用如下命令進(jìn)行調(diào)試命令進(jìn)行調(diào)試(gdb) ad
60、d-symbol-file ./scull.ko 0 xd0832000 -s .bss 0 xd0837100 -s .data 0 xd0836be050調(diào)試器和相關(guān)工具調(diào)試器和相關(guān)工具例例 scull調(diào)試調(diào)試(gdb) add-symbol-file scull.ko 0 xd0832000 -s .bss 0 xd0837100 -s .data 0 xd0836be0add symbol table from file scull.ko at .text_addr = 0 xd0832000 .bss_addr = 0 xd0837100 .data_addr = 0 xd0836be0(y or n) yReading symbols from scu
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二手房交易資金監(jiān)管及配套服務(wù)協(xié)議
- 影視動畫角色形象授權(quán)及衍生品生產(chǎn)合作協(xié)議
- 子女海外留學(xué)經(jīng)費(fèi)分擔(dān)與教育支持協(xié)議
- 綠色環(huán)保物流配送站運(yùn)營管理委托協(xié)議
- 海外留學(xué)生醫(yī)療保險直付醫(yī)院合作協(xié)議
- 智能制造工業(yè)廠房租賃及智能制造系統(tǒng)協(xié)議
- 拼多多品牌店鋪代運(yùn)營服務(wù)協(xié)議涵蓋倉儲物流與配送
- 市場代理區(qū)域市場調(diào)研報告補(bǔ)充協(xié)議
- 耕地規(guī)?;N植與現(xiàn)代農(nóng)業(yè)合作管理協(xié)議
- 教育機(jī)構(gòu)教材管理及派遣專業(yè)團(tuán)隊服務(wù)合同
- 2025年高考語文作文終極押題03 關(guān)于Deepseek(押題理由+作文真題++審題立意+高分范文)(全國)
- 運(yùn)動素質(zhì)知到課后答案智慧樹章節(jié)測試答案2025年春浙江大學(xué)
- 租房合同范本下載(可直接打印)
- 福州市歷史建筑保護(hù)管理辦法(試行)
- JHA及SCL風(fēng)險評價方法講解(參考)
- DB11T 1933-2021 人乳庫建立與運(yùn)行規(guī)范
- 1.3.1動量守恒定律課件(共13張PPT)
- 國網(wǎng)北京市電力公司授權(quán)委托書(用電)
- 中小學(xué)教育懲戒規(guī)則(試行)全文解讀ppt課件
- 常暗之廂(7規(guī)則-簡體修正)
- 終端塔基礎(chǔ)預(yù)偏值(抬高值)計算表格
評論
0/150
提交評論