1. 程式人生 > >linux核心除錯環境搭建-3 除錯核心模組

linux核心除錯環境搭建-3 除錯核心模組

在虛擬機器中 建立兩個指令碼get.sh:

tftp 192.168.100.1 -g -r $1

put.sh:

tftp 192.168.100.1 -p -l $1

在linux裝置驅動開發詳解中原始碼:

/*======================================================================
    A globalmem driver as an example of char device drivers  
   
    The initial developer of the original code is Baohua Song
    <
[email protected]
>. All Rights Reserved. ======================================================================*/ #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/slab.h> #define GLOBALMEM_SIZE 0x1000 /*全域性記憶體最大4K位元組*/ #define MEM_CLEAR 0x1 /*清0全域性記憶體*/ #define GLOBALMEM_MAJOR 245 /*預設的globalmem的主裝置號*/ static globalmem_major = GLOBALMEM_MAJOR; /*globalmem裝置結構體*/ struct globalmem_dev { struct cdev cdev; /*cdev結構體*/ unsigned char mem[GLOBALMEM_SIZE]; /*全域性記憶體*/ }; struct globalmem_dev *globalmem_devp; /*裝置結構體指標*/ /*檔案開啟函式*/ int globalmem_open(struct inode *inode, struct file *filp) { /*將裝置結構體指標賦值給檔案私有資料指標*/ filp->private_data = globalmem_devp; return 0; } /*檔案釋放函式*/ int globalmem_release(struct inode *inode, struct file *filp) { return 0; } /* ioctl裝置控制函式 */ static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { struct globalmem_dev *dev = filp->private_data;/*獲得裝置結構體指標*/ switch (cmd) { case MEM_CLEAR: memset(dev->mem, 0, GLOBALMEM_SIZE); printk(KERN_INFO "globalmem is set to zero\n"); break; default: return - EINVAL; } return 0; } /*讀函式*/ static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev = filp->private_data; /*獲得裝置結構體指標*/ /*分析和獲取有效的寫長度*/ if (p >= GLOBALMEM_SIZE) return count ? - ENXIO: 0; if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; /*核心空間->使用者空間*/ if (copy_to_user(buf, (void*)(dev->mem + p), count)) { ret = - EFAULT; } else { *ppos += count; ret = count; printk(KERN_INFO "read %d bytes(s) from %d\n", count, p); } return ret; } /*寫函式*/ static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev = filp->private_data; /*獲得裝置結構體指標*/ /*分析和獲取有效的寫長度*/ if (p >= GLOBALMEM_SIZE) return count ? - ENXIO: 0; if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; /*使用者空間->核心空間*/ if (copy_from_user(dev->mem + p, buf, count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "written %d bytes(s) from %d\n", count, p); } return ret; } /* seek檔案定位函式 */ static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig) { loff_t ret = 0; switch (orig) { case 0: /*相對檔案開始位置偏移*/ if (offset < 0) { ret = - EINVAL; break; } if ((unsigned int)offset > GLOBALMEM_SIZE) { ret = - EINVAL; break; } filp->f_pos = (unsigned int)offset; ret = filp->f_pos; break; case 1: /*相對檔案當前位置偏移*/ if ((filp->f_pos + offset) > GLOBALMEM_SIZE) { ret = - EINVAL; break; } if ((filp->f_pos + offset) < 0) { ret = - EINVAL; break; } filp->f_pos += offset; ret = filp->f_pos; break; default: ret = - EINVAL; break; } return ret; } /*檔案操作結構體*/ static const struct file_operations globalmem_fops = { .owner = THIS_MODULE, .llseek = globalmem_llseek, .read = globalmem_read, .write = globalmem_write, .ioctl = globalmem_ioctl, .open = globalmem_open, .release = globalmem_release, }; /*初始化並註冊cdev*/ static void globalmem_setup_cdev(struct globalmem_dev *dev, int index) { int err, devno = MKDEV(globalmem_major, index); cdev_init(&dev->cdev, &globalmem_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &globalmem_fops; err = cdev_add(&dev->cdev, devno, 1); if (err) printk(KERN_NOTICE "Error %d adding LED%d", err, index); } /*裝置驅動模組載入函式*/ int globalmem_init(void) { int result; dev_t devno = MKDEV(globalmem_major, 0); /* 申請裝置號*/ if (globalmem_major) result = register_chrdev_region(devno, 1, "globalmem"); else /* 動態申請裝置號 */ { result = alloc_chrdev_region(&devno, 0, 1, "globalmem"); globalmem_major = MAJOR(devno); } if (result < 0) return result; /* 動態申請裝置結構體的記憶體*/ globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL); if (!globalmem_devp) /*申請失敗*/ { result = - ENOMEM; goto fail_malloc; } memset(globalmem_devp, 0, sizeof(struct globalmem_dev)); globalmem_setup_cdev(globalmem_devp, 0); return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result; } /*模組解除安裝函式*/ void globalmem_exit(void) { cdev_del(&globalmem_devp->cdev); /*登出cdev*/ kfree(globalmem_devp); /*釋放裝置結構體記憶體*/ unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*釋放裝置號*/ } MODULE_AUTHOR("Song Baohua"); MODULE_LICENSE("Dual BSD/GPL"); module_param(globalmem_major, int, S_IRUGO); module_init(globalmem_init); module_exit(globalmem_exit);

其makefile檔案:

obj-m	+= globalmem.o
KDIR	= /home/gudujian/work/linux-2.6.35.9

EXTRA_CFLAGS=-g -O0

build:kernel_modules

kernel_modules:
	make -C $(KDIR) M=$(CURDIR) modules


clean:
	make -C $(KDIR) M=$(CURDIR) clean 

其中KDIR為編譯核心時使用的目錄。

指令碼 section.sh 內容:

#
# gdbline module image
#
# Outputs an add-symbol-file line suitable for pasting into gdb to examine
# a loaded module.
#
cd /sys/module/$1/sections
echo -n add-symbol-file  `/bin/cat .text`

for section in .[a-z]* *; do
    if [ $section != ".text" ]; then
	echo  " \\"
	echo -n "	-s" $section `/bin/cat $section`
    fi
done
echo

將得到的檔案編譯結果,globalmem.ko;以及指令碼section.sh 通過tftp方式拷貝到工作目錄:

#./get.sh globalmem.ko

#./get.sh section.sh

在主機的tftpboot目錄下建立一個檔案gdb,許可權777.

用如下指令碼啟動虛擬機器:

qemu -m 512 -kernel bzImage -append "root=/dev/sda kgdboc=ttyS0,115200 kgdbwait" -boot c -hda busybox.img -k en-us -net nic -net tap,ifname=tap0,script=no -serial tcp::4321,server

另開一個終端:

$cd /dir/to/linux-2.6.35.9

$gdb vmlinux

顯示如下:

Reading symbols from /home/gudujian/work/linuxker/linux-2.6.35.9/vmlinux...done.

(gdb)

gdb命令

(gdb) target remote localhost:4321

Remote debugging using localhost:4321

kgdb_breakpoint (new_dbg_io_ops=0xc07c27e0) at kernel/debug/debug_core.c:967

warning: Source file is more recent than executable.

967            wmb(); /* Sync point after breakpoint */

在主機終端按c讓qemu虛擬機器啟動執行:

在qemu的虛擬機器中載入模組globalmem.ko

#insmod globalmem.ko

用section.sh指令碼得到gdb符號檔案:

#./section.sh globalmem > gdb

將gdb符號檔案拷貝到主機中:

#./put.sh gdb

讓虛擬機器進入除錯模式:

#echo g >/proc/sysrq-trigger

/tftpboot/gdb 修改前後的內容分別是:

add-symbol-file 0xe0a35000 \
        -s .bss 0xe0a35834 \
        -s .data 0xe0a356b8 \
        -s .gnu.linkonce.this_module 0xe0a356c0 \
        -s .note.gnu.build-id 0xe0a35540 \
        -s .rodata 0xe0a35580 \
        -s .strtab 0xe0a38430 \
        -s .symtab 0xe0a38000 \
        -s __mcount_loc 0xe0a35690 \
        -s __param 0xe0a3567c
add-symbol-file /dir/to/globalmem.ko  0xe0a35000 \
        -s .bss 0xe0a35834 \
        -s .data 0xe0a356b8 \
        -s .gnu.linkonce.this_module 0xe0a356c0 \
        -s .note.gnu.build-id 0xe0a35540 \
        -s .rodata 0xe0a35580 \
        -s .strtab 0xe0a38430 \
        -s .symtab 0xe0a38000 \
        -s __mcount_loc 0xe0a35690 \
        -s __param 0xe0a3567c

此時在除錯端輸入命令:

(gdb) source /tftpboot/gdb

下兩個斷點:

(gdb) b globalmem_write

Breakpoint 1 at 0xe0a351cf: file /dir/to/globalmem.c, line 100.

(gdb) b globalmem_read

Breakpoint 2 at 0xe0a350fc: file /dir/to/globalmem.c, line 100.

然後c讓qemu執行。

在qemu中建立一個裝置節點globalmem:

#mknod /dev/globalmem c 245 0

(這裡的主裝置號跟原始碼裡的相同)

在qemu中給節點/dev/globalmem輸入 hello driver world:

#echo “hello driver world” > /dev/globalmem

此時主機中斷在globalmem_write

(gdb) c

Continuing.

Breakpoint 1, globalmem_write (filp=0xdfa96080,

    buf=0x854c740 "hello driver world\n", size=19, ppos=0xdfbcbf98)

    at /home/gudujian/06/globalmemDriver/globalmem.c:100

100           unsigned long p =  *ppos;

此時檢視變數:

(gdb) p buf

$3 = 0x854c740 "hello driver world\n"

(gdb) p /x size

$4 = 0x13                  //字串長度

(gdb) p *ppos

$5 = 0

如果有興趣可往下跟蹤,這裡略去,直接c了。

同理也可以用同樣的方式來除錯核心模組的其它函式。

碼字不容易,覺得好請打賞下:

相關推薦

linux核心除錯環境搭建-3 除錯核心模組

在虛擬機器中 建立兩個指令碼get.sh: tftp 192.168.100.1 -g -r $1 put.sh: tftp 192.168.100.1 -p -l $1 在linux裝置驅動開發詳解中原始碼: /*=========================

Phpstorm+XAMPP+Xdebug搭建斷點除錯環境 搭建php除錯開發環境

開發環境 php整合工具:xampp v3.2.2 PHP Version: 7.2.11 PhpStorm:2017.3.4 一、下載安裝Xdebug軟體 可去官方網站下載 http://xdebug.org/ 注意下載的版本一定要與你本地的php版本一

Win7雙機除錯環境搭建除錯

  轉:http://www.16boke.com/article/detail/174 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適

linux核心除錯環境搭建

版本linux4.17 ubuntu18.04先給系統至少80G記憶體1。編譯核心先配置檔案make mrpropermake menuconfig我這裡需要的依賴有 sudo apt install make cmake gcc g++ clang sudo apt-get install libnc

linux-2-6-11核心除錯環境搭建

linux核心除錯環境分為兩部分 1)用bochs除錯彙編 2)用qemu除錯從start_kernel開始的部分 環境說明: 核心版本: 2.6.11 ubuntu: 6.10 qemu: qemu-stable-0.13 busybox: 1.10.4 安裝ubuntu

Linux核心除錯環境搭建(基於ubuntu12.04)

by Netfairy - 2016-05-29 一、測試環境 物理機:ubuntu16.04 LTS target(被除錯機)環境:VirtualBox 5.0.20+ubuntu 12.04 LTS + linux kernel 3.0.4 host

linux核心除錯環境搭建-2 用busybox搭建

下載linux核心: $cd ~/work/ $wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.35.9.tar.bz2 解壓 $tar -jxvf linux-2.6.35.9.tar.bz2

linux核心除錯環境搭建-

kvm系統的前端是qemu-kvm,工作在使用者空間,給使用者提供一套方便的kvm虛擬化工具集合。下面來介紹一下qemu-kvm-0.11.0的編譯過程。 1、下載 wget http://sourceforge.net/projects/kvm/files/qemu-kvm/0.11.0/qem

Linux下的 ARM裸機除錯環境搭建(GDB + JLink)

說明:我也是除錯u-boot,在win下OK了,基於這裡,然後為了完全在linux下便有了下邊轉載的內容。下文會對照我自己的操作進行結果補充!感覺補充的多於轉載的就改為原創了,讓更多人看到!     一直想擺脫windows環境,在純linux下進行arm裸機開發,

(轉載)純Linux下的 ARM裸機除錯環境搭建(GDB + JLink)

一直想擺脫windows環境,在純linux下進行arm裸機開發,但是由於一直不知道JLink如何在linux下執行和配置,一直無法進行下去。以前都是windows+AXD除錯。包括本人用的FL2440開發板和JLink偵錯程式也沒有提供在linux除錯的文件。前些天由於想

Spring原始碼分析——除錯環境搭建(可能是最省事的構建方法)

1. 依賴工具 idea git jdk 1.8 + Gradle 2. 獲取原始碼   從github https://github.com/spring-projects/spring-framework 上 Fork 出屬於自己的倉庫。如果懶得這麼做也可以

centos5 下 lida 除錯環境搭建

1.下載lida, site:http://lida.sourceforge.net/(需翻牆) 2. 解壓lida-03.00.00.tgz 3. make 4. 執行lida 成功了!! 遇到的問題: 1. 報Tk沒安裝 [[email p

esp8266~入坑sdk 3.0 IDF框架和linux交叉編譯環境搭建

一、交叉編譯環境搭建步驟 1、安裝virtualbox、ubuntu虛擬機器共享windows資料夾,注!virtualbox最好裝在C盤,不然安裝虛擬工具經常會失敗。 2、新建共享目錄,掛載共享目錄到虛擬機器中 sudo mount -t vboxsf share /mn

Win7雙機除錯環境搭建之常見問題

轉:http://www.16boke.com/article/detail/175 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適合除錯機的相應位數

Win7雙機除錯環境搭建之配置WinDbg

  轉:http://www.16boke.com/article/detail/173 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適

Win7雙機除錯環境搭建之配置GuestOS的啟動項

轉:http://www.16boke.com/article/detail/172 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適合除錯機的相應位數

Win7雙機除錯環境搭建之配置VMware的管道虛擬串列埠

轉:http://www.16boke.com/article/detail/171 WinDbg除錯核心時,被設計為雙機除錯,需要另一臺計算機(除錯機)來除錯被除錯的計算機(被除錯機),WinDbg必須安裝在除錯機上,除錯機與被除錯機通過串列埠相連線。   環境: 主機:

Netflix Eureka原始碼除錯環境搭建

一:下載Gradle,從官網下載就可以了,非常簡單 (1)https://gradle.org/releases/,從這個地址去下載 (2)我下載的gradle-2.10-bin.zip,然後你找個目錄,解壓縮,比如我的目錄是:F:\development\gradle\

PhpStorm Xdebug遠端除錯環境搭建原理分析及問題排查

http://blog.nsfocus.net/phpstorm-xdebug-remote-debugging-troubleshooting/ 對於簡單的工程,直接print_r();exit()已經足夠,但是對於大型專案有時就有點力不從心,如果直接將apache部署在本地,phpstorm除錯

RocketMQ原始碼分析(一)之除錯環境搭建

版本宣告 基於rocketmq-all-4.3.1版本 所有分析是根據自己的理解,因為不是RocketMQ的原始開發者,所以肯定會存在分析不正確的地方,如有發現歡迎指正,謝謝! 規定$ROCKET