Vim浏览linux kernel代码的环境搭建

本文介绍了如何在Ubuntu 14.04环境下安装Vim 8.0.69,配置常用插件如ctags、NERDTree、TagList等,以实现Linux内核代码的浏览、符号跳转、自动补全等功能,从而替代SourceInsight。详细步骤包括下载、编译Vim,安装exuberant-ctags,配置.vimrc文件,以及安装YouCompleteMe和cscope等工具,最终创建一个高效的Linux内核代码编辑环境。

0x1 概述

前一段时间下载了linuxkernel 4.1的源码,用sourceinsight创建工程进行同步,每次都会报错,以前的工程都没问题,更重要的一点是我越来越反感windows系统,所以就想用vim完全代替sourceinsightvim其实很强大,一直使用却从来没有深入过,正好趁机研究一下。

主机环境:ubuntu14.04 + vim 8.0.69

实现功能:目录树、当前文件符号列表、全局符号索引、自动补全、文件索引、自动缩进、历史文件列表、代码编译


0x2 安装vim

安装vim的新版本出于ycm(youcompleteme)插件的要求,这个插件提供强大的自动补全功能,如果不需要这个插件,或者你的vim版本已经符合ycm的要求,本节可以直接略过,对vim的版本要求可以在ycmREADME.md中可以找到。

0x21 vim下载解压

下载地址

http://www.vim.org/download.php

删除系统自带的vim

sudo apt-get purge vim

解压vim源码:

tar -jxvf vim-8.0.tar.bz2

0x22 配置编译

进入源码目录:

cd vim80/src/

打开Makefile文件,添加对python的支持,配置已经写好,去掉下面四项注释即可

CONF_OPT_PYTHON =--enable-pythoninterp
CONF_OPT_PYTHON =--enable-pythoninterp=dynamic
CONF_OPT_PYTHON3 =--enable-python3interp
CONF_OPT_PYTHON3 =--enable-python3interp=dynamic

配置编译:

make

sudo make install

0x23 查看vim版本

vim --version


0x3 常用插件

0x31 ctags

作用

生成tag文件用于宏定义、变量、函数等符号跳转。

下载地址

https://sourceforge.net/projects/ctags/files/latest/download?source=files

遇到的问题

taglist需要使用ctags,但是与vim自带的ctags不兼容,当配置taglist插件后,打印如下错误:

ctags: unrecognized option'--format=2'^@^ITry `ctags --help'

必须通过安装exuberant-ctags解决

sudo agt-get installctags-exuberant

同时在.vimrc中为taglist设置该工具的二进制文件路径

let Tlist_Ctags_Cmd ='/usr/bin/ctags-exuberant'

生成符号文件

linux内核代码根目录执行下面命令

cd ~/src/kernel/linux-3.16$

~/src/kernel/linux-3.16$ maketags

使用方法

vim默认会在当前目录查找名字为”tags”tag文件。一旦建立了tag文件,运用下面的命令索引tag

vim –t tag

打开当前目录下tag所在的定义位置,如果没有则进入vim后报错

:ta tag

查找tag

ctrl + ]

查找光标下的tag

ctrl + T

返回之前的位置

0x32 NERDTree

作用

建立源码目录树

下载地址

http://www.vim.org/scripts/script.php?script_id=1658

安装

unzip解压NERD_tree.zipcopydoc/NERD_tree.txt到目录~/.vim/doc/下,copyNERD_tree.vim~/.vim/plugin/下,copyautoload/,lib/, nerdtree_plugin/, syntax/几个目录到~/.vim/目录下

使用方法

运行vim,输入:NERDTree命令,即可列出当前目录的目录树,如图:


3.1 NERDTree运行效果

适配winmanager插件

此处有一个问题,NERDTree加入winmanager多一个空白窗口,所以NERDTree_Start函数先执行一个退出命令

let g:NERDTree_title ="\/[NERDTree\/]"
function! NERDTree_Start()
    exe 'q'
    exe 'NERDTree'
endfunction

“ never change, return 0
function! NERDTree_IsValid()
    return 0
endfunction

常用操作

ctrl + w + h  光标focus左侧树形目录

ctrl + w + l  光标focus右侧文件显示窗口

ctrl + w + w  光标自动在左右侧窗口切换

ctrl + w + r  移动当前窗口的布局位置

O  递归打开选中结点下的所有目录

x  合拢选中结点的父目录

X  递归合拢选中结点下的所有目录

P  跳到根结点

p  跳到父结点

K  跳到当前目录下同级的第一个结点

J  跳到当前目录下同级的最后一个结点

k 跳到当前目录下同级的前一个结点

j  跳到当前目录下同级的后一个结点

0x33 TagList

作用

显示当前文件的tag列表

下载地址

http://www.vim.org/scripts/script.php?script_id=273

安装

解压后copytaglist.txt~/.vim/doc/下,copytaglist.vim~/.vim/plugin/

vimrc配置

"设置ctags二进制文件路径

let Tlist_Ctags_Cmd ='/usr/bin/ctags-exuberant'

"只显示当前buffertags信息

let Tlist_Show_One_File = 1

"vim退出时,一并退出

let Tlist_Exit_OnlyWindow = 1

"自动关闭非焦点窗口的tag信息

let Tlist_File_Fold_Auto_Close= 1

"taglistvim右侧,加入winmanager后,位置由winmanager管理

let Tlist_Use_Right_Window = 1

"显示tags menu

"let Tlist_Show_Menu = 1

"vim运行时打开

"let Tlist_Auto_Open = 1

使用方法

<CR>  回车键,跳转到光标下的tag的定义处

o  跳转到光标下的tag的定义处,在新窗口中显示

P  跳转到tag处,在上一个窗口中显示

p  在文件中显示tag的定义位置,光标停留在taglist中原位置

t  在新标签页中跳转到tag。如果tag所在的文件已经打开了,则移动到该文件

Ctrl-t  在新标签页中跳转到tag

<Space>  显示光标处tag的原型。如果是文件名,则显示文件的完整路径,文件类型和tags数量。如果是tag类型,则显示tag类型和tags数量

u  更新tags列表

s  改变tags排列顺序(按名称或按文件中出现的次序)

d  移除光标处文件的tags

x  放大或缩小taglist窗口

+  打开一个折叠

-  关闭一个折叠

*  打开所有的折叠

=  关闭所有的折叠

q  关闭taglist窗口

<F1>  显示帮助


图3.2 taglist运行效果

0x34 bufexplorer

作用

buffer列表,查看历史打开文件

下载地址

http://www.vim.org/scripts/script.php?script_id=42

安装

TagList

遇到的问题

bufexplorer会根据历史条目数量自适应窗口高度,但是taglist没有同样的实现,导致切换回taglist功能时,窗口高度无法恢复(此处涉及到taglistbufexplorer功能重叠的问题,winmanager会讲到)


3.3 bufexplorer自适应窗口高度

解决方法

目前不需要这个feature,所以干脆直接注释掉在bufexplorer.vim脚本中function!BufExplorer_ReSize()函数。

如果bufexplorer.vim的格式是dos,GNU/Linux下必须转换成unix文本格式,转换方法

sed 's/.$//' -i bufexplorer.vim

或者

vim bufexplorer.vim

:set fileformat=unix

:w

适配winmanager

bufexplorer.vim已经实现了BufExplorer_StartBufExplorer_IsValidBufExplorer_Refresh三个函数。

0x35 winmanager

作用

管理多个插件的显示布局

下载解压

http://www.vim.org/scripts/script.php?script_id=1440

bunzip2 winmanager.vmb.bz2

安装

执行~/tftp_root$vim winmanager.vmb后弹出如下提示:


3.4 vimball运行

输入:so%完成安装:


3.5 vimball安装winmanager

vimrc配置

"winmanager

"设置窗口布局

let g:winManagerWindowLayout ='NERDTree|TagList,BufExplorer'

"所有文件关闭,只剩资源管理窗口时,退出vim

let g:persistentBehaviour = 0

"设置子窗口的宽为30,默认25

let g:winManagerWidth = 30

let g:defaultExplorer = 0

"映射winmanager开关

nmap wm :WMToggle<cr>

"直接移动焦点到左上角窗口

nmap fw:FirstExplorerWindow<cr>

"直接移动焦点到右下角窗口

nmap bw:BottomExplorerWindow<cr

使用方法

cd~/src/linux/kernel/linux-3.16$

vim

打开winmanager

:wm

移动到左上角窗口

:fw


3.6 winmanager运行效果图

特别注意:TagListBufExplorer在同意区域显示,切换功能的方法是ctrl+n

0x36 YouCompleteMe

作用

自动补全

下载

cd /.vim/plugin/

git clone --recursive https://github.com/Valloric/YouCompleteMe.git

确认仓库的完整性

git submodule update --init --recursive

系统要求

ycm根目录的README.mdUbuntuLinux x64部分写明了对vimpython的版本要求最新的ycm要求Vim7.4.143版本及以上,并且支持Python2Python3,在第一节已经介绍过了

安装依赖的软件包

sudo apt-get install build-essential cmake

sudo apt-get install python-dev python3-dev

手动安装

下载clang地址

http://releases.llvm.org/3.9.0/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz

解压

tar -xvfclang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz

cd ~

mkdir ycm_build

cd ycm_build

生成makefile

cmake -G "Unix Makefiles"-DPATH_TO_LLVM_ROOT=~/ycm_temp/llvm_root_dir . ~/.vim/plugin/YouCompleteMe/third_party/ycmd/cpp

编译

make

快速安装

只针对c家族语言的语义支持

cd ~/.vim/plugin/YouCompleteMe

./install.py–clang-completer

正确安装后如下:


3.7 ycm安装完成

打开~/.vim/plugin/YouCompleteMe/third_party/ycmd/cpp/ycm/.ycm_extra_conf.py文件,做如下修改

注释掉gmock相关配置

#'-isystem',
#'./tests/gmock/gtest',
#'-isystem',
#'./tests/gmock/gtest/include',
#'-isystem',
#'./tests/gmock',
#'-isystem',
#'./tests/gmock/include',

增加linux内核的配置

'-isystem',
'/usr/arm-linux-gnueabi/include',
'-isystem',
'~/src/linux/kernel/linux-3.16/include',
'-isystem',
'~/src/linux/kernel/linux-3.16/include/linux',

vimrc配置

"Vim的补全菜单行为与一般IDE一致(参考VimTip1228)

set completeopt=longest,menu

set completeopt-=preview

"配置ycm_extra_conf.py路径

letg:ycm_global_ycm_extra_conf='~/.vim/plugin/YouCompleteMe/third_party/ycmd/cpp/ycm/.ycm_extra_conf.py'

"开启语义补全

letg:ycm_seed_identifiers_with_syntax = 1

" 禁止缓存匹配项,每次都重新生成匹配项

let g:ycm_cache_omnifunc=0

"ycm首先通过ultisnips进行代码块补全,这里没有该插件,并且默认为1,所以要设置为0关掉功能

letg:ycm_use_ultisnips_completer=0

"开启基于tag的补全,可以在这之后添加需要的标签路径

let g:ycm_collect_identifiers_from_tags_files= 1

" 输入第2个字符开始补全

let g:ycm_min_num_of_chars_for_completion= 2

" 不进行错误诊断

let g:ycm_show_diagnostics_ui= 0

回车即选中

inoremap <expr> <CR> pumvisible() ? "\<C-y>" : "\<CR>"

0x37 cscope

作用

全局符号和文件查找

安装

sudo apt-get install cscope

        cscope命令

        s 查找C符号,包括函数名、宏、变量名、枚举等

        g 全局范围内查找符号定义位置

        d 查找本函数调用的函数

        c 查找调用本函数的函数

        t 查找字符串

        e 查找egrep匹配字符串,egrep命令等同于grep -E,利用此命令可以使用扩展的正则表达式对文本进行搜索

        f 查找并打开文件

        i 查找包含本文件的文件

生成符号文件

cd ~/src/kernel/linux-3.16

make cscope

ls -l cscope* 多了scope开头的几个文件

vimrc配置

vim打开时加载cscope索引文件

if has("cscope")
    setcsprg=/usr/local/bin/cscope
    set csto=0
    set cst
    set nocsverb
    " add any database incurrent directory

    if filereadable("cscope.out")
        cs add cscope.out
    " else add databasepointed to by environment
    elseif $CSCOPE_DB != ""
        cs add $CSCOPE_DB
    endif
    set csverb
endif

按键功能映射

nmap <C-_>s :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>g :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>c :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>t :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>e :cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-_>i :cs find i <C-R>=expand("<cfile>")<CR><CR>
nmap <C-_>d :cs find d <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>a :cs find a <C-R>=expand("<cword>")<CR><CR>

按键方法是把光标停留在要查找的关键字或文件名处,先按"Ctrl+Shift+-"然后再按对应的字母。


0x4 针对linux内核codingstyle的配置

filetype plugin indent on

syn on se title

set tabstop=8

set softtabstop=8

set shiftwidth=8

set noexpandtab


0x5 vim中进行编译

vimrc中添加如下函数:

func! CompileLK()
    exec "w"
    exec "makeCROSS_COMPILE=arm-linux-gnueabi- ARCH=arm zImage"
endfunc

该函数先保存当前文件,然后执行编译

映射编译命令:

map mk :call CompileLK()<CR>

输入:mk命令执行保存编译动作


0x6 完整的.vimrc

"set mouse=a

"if you are using ycm,backspace can't be used normally, so set backspace as
"below
set backspace=2
set syntax=on

" codeing style setting
filetype plugin indent on
syn on se title
set tabstop=8
set softtabstop=8
set shiftwidth=8
set noexpandtab

" taglist setting
let Tlist_Ctags_Cmd ='/usr/bin/ctags-exuberant'
let Tlist_Show_One_File = 1
let Tlist_Exit_OnlyWindow = 1
let Tlist_File_Fold_Auto_Close= 1
let Tlist_Use_Right_Window = 1
"let Tlist_Show_Menu = 1
"let Tlist_Auto_Open = 1

" winmanager setting
let g:winManagerWindowLayout ='NERDTree|TagList,BufExplorer'
let g:persistentBehaviour = 0
let g:winManagerWidth = 30
let g:defaultExplorer = 0
nmap wm :WMToggle<cr>
nmap fw:FirstExplorerWindow<cr>
nmap bw:BottomExplorerWindow<cr>

" compilation setting
func! CompileLK()
    exec "w"
    exec "makeCROSS_COMPILE=arm-linux-gnueabi- ARCH=arm zImage"
endfunc

map mk :call CompileLK()<CR>

" ycm setting
set completeopt=longest,menu
set completeopt-=preview
let g:ycm_global_ycm_extra_conf='~/.vim/plugin/YouCompleteMe/third_party/ycmd/cpp/ycm/.ycm_extra_conf.py'
let g:ycm_seed_identifiers_with_syntax=1
let g:ycm_cache_omnifunc=0
let g:ycm_use_ultisnips_completer=0
let g:ycm_collect_identifiers_from_tags_files=1
let g:ycm_min_num_of_chars_for_completion=2
let g:ycm_show_diagnostics_ui =0
autocmd InsertLeave * ifpumvisible() == 0|pclose|endif

inoremap <expr> <CR>pumvisible() ? "\<C-y>" : "\<CR>"

"cscope setting
if has("cscope")
    set csprg=/usr/bin/cscope
    set csto=1
    set cst
    set nocsverb

    "add any database incurrent directory
    if filereadable("cscope.out")
        cs add cscope.out
    endif
    set csverb
endif

nmap <C-_>s :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>g :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>c :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>t :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>e :cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <C-_>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-_>i :cs find i <C-R>=expand("<cfile>")<CR><CR>
nmap <C-_>d :cs find d <C-R>=expand("<cword>")<CR><CR>


参考资料

vim插件安装及配置

http://www.cnblogs.com/ifys/archive/2010/10/24/1860610.html

http://blog.csdn.net/bokee/article/details/6633193

linux内核浏览编辑器及环境设置

https://kernelnewbies.org/FAQ/CodeBrowsing

https://kernelnewbies.org/KernelHackingTools

https://kernelnewbies.org/FirstKernelPatch#head-17dd753ec497c8f7e2305ce78be8c6ca7cd1c92c

ycm安装配置

http://www.linuxidc.com/Linux/2014-04/99719.htm

http://blog.csdn.net/houzhuoming1/article/details/49990739

http://www.cnblogs.com/Suzzz/p/4071880.html

http://www.tuicool.com/articles/QBnAr2


<think>我们被要求回答如何在Linux上配置和搭建kernel gdb调试环境。根据提供的引用,我们可以总结出以下步骤: 1. 编译内核:需要配置和编译内核,以便带有调试信息。 2. 制作根文件系统(rootfs):可以使用busybox来制作一个简单的根文件系统。 3. 使用QEMU启动编译好的内核和根文件系统。 4. 使用GDB连接QEMU进行调试。 我们将按照这些步骤详细说明。 步骤1:编译内核 - 下载内核源码(可以从官网或git仓库获取) - 配置内核,确保开启调试信息(在配置中,Kernel hacking -> Compile-time checks and compiler options -> 选中Compile the kernel with debug info) - 编译内核 步骤2:制作根文件系统 - 下载busybox源码并编译 - 创建rootfs目录,将busybox安装到该目录 - 创建必要的设备文件(如/dev/console等)和初始化脚本(如init) 步骤3:使用QEMU启动内核 - 使用QEMU命令启动内核,指定内核镜像和rootfs,并开启调试端口(例如:-S -s 表示暂停CPU并监听1234端口) 步骤4:使用GDB调试 - 在另一个终端启动GDB,加载内核符号表(vmlinux- 连接到QEMU(target remote:1234) - 设置断点(如b start_kernel)进行调试 下面我们详细展开每个步骤。 ### 详细步骤 #### 1. 编译内核 假设我们使用linux-5.4.34版本的内核。 ```bash # 下载内核源码(示例使用wget,也可以使用git) wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz tar xvf linux-5.4.34.tar.xz cd linux-5.4.34 # 配置内核,可以选择默认配置(如x86_64_defconfig)并开启调试信息 make x86_64_defconfig # 使用menuconfig打开配置菜单,确保调试信息开启 make menuconfig ``` 在menuconfig中,定位到: Kernel hacking ---> Compile-time checks and compiler options ---> [*] Compile the kernel with debug info 保存配置后编译: ```bash make -j$(nproc) # 使用多核编译 ``` 编译完成后,内核镜像文件为`arch/x86/boot/bzImage`(以x86架构为例),同时,符号表文件为当前目录下的`vmlinux`。 #### 2. 制作根文件系统 使用busybox制作一个简单的rootfs。 首先下载并编译busybox: ```bash wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2 tar xvf busybox-1.32.1.tar.bz2 cd busybox-1.32.1 make menuconfig ``` 在busybox配置中,确保设置为静态编译: Settings ---> [*] Build static binary (no shared libs) 然后编译并安装到rootfs目录: ```bash make -j$(nproc) && make install ``` 接下来创建rootfs目录结构: ```bash cd .. mkdir rootfs cd rootfs cp -r ../busybox-1.32.1/_install/* . mkdir dev proc sys sudo mknod dev/console c 5 1 sudo mknod dev/ram b 1 0 sudo mknod dev/sda b 8 0 # 如果需要模拟磁盘设备 ``` 创建init文件(rootfs目录下): ```bash touch init chmod +x init ``` init文件内容示例: ```bash #!/bin/sh echo "Welcome to my Linux!" mount -t proc none /proc mount -t sysfs none /sys mount -t devtmpfs none /dev echo /sbin/mdev > /proc/sys/kernel/hotplug mdev -s exec /bin/sh ``` 然后使用以下命令生成根文件系统的镜像文件(例如ext4格式): ```bash dd if=/dev/zero of=rootfs.img bs=1M count=100 mkfs.ext4 rootfs.img sudo mkdir -p /mnt/rootfs sudo mount rootfs.img /mnt/rootfs sudo cp -r rootfs/* /mnt/rootfs/ sudo umount /mnt/rootfs ``` 这样我们就得到了rootfs.img。 #### 3. 使用QEMU启动 使用QEMU启动内核,并挂载根文件系统。同时,开启调试端口(1234)并暂停CPU等待调试器连接。 ```bash qemu-system-x86_64 \ -kernel linux-5.4.34/arch/x86/boot/bzImage \ -drive file=rootfs.img,if=ide,format=raw \ -append "root=/dev/sda console=ttyS0" \ -nographic \ -S -s ``` 解释: - `-kernel`:指定内核镜像 - `-drive`:指定根文件系统镜像 - `-append`:内核启动参数,指定根设备为/dev/sda(IDE磁盘)和控制台 - `-nographic`:不使用图形界面 - `-S`:启动时暂停CPU - `-s`:监听TCP端口1234(gdb默认端口) #### 4. 使用GDB调试 打开另一个终端,进入内核源码目录,启动gdb: ```bash cd linux-5.4.34 gdb vmlinux ``` 在gdb中连接QEMU: ```bash (gdb) target remote :1234 ``` 设置断点(例如在start_kernel): ```bash (gdb) b start_kernel ``` 继续执行: ```bash (gdb) c ``` 然后就可以进行调试了。 ### 注意事项 1. 在调试过程中,可能会遇到寄存器显示问题(如引用[5]所述),这是因为局部变量可能被优化到寄存器中,而gdb显示的是寄存器的值,但实际内存中的变量可能没有改变。这需要结合代码上下文理解。 2. 如果需要调试模块(module),需要确保模块也带有调试信息,并且在启动时加载。在QEMU启动参数中,可以通过-initrd指定包含模块的initramfs,或者通过其他方式加载。 以上步骤搭建了一个基本的调试环境。 §§相关问题§§ 1. 如何在内核调试中设置断点? 2. 如何调试Linux内核模块? 3. 在QEMU中如何配置网络以便调试?</think>### 如何在 Linux 上配置和搭建 Kernel GDB 调试环境 以下是基于 QEMU 和 GDB 的内核调试环境搭建步骤(以 **Ubuntu 20.04** 为例): --- #### **1. 编译 Linux 内核** ```bash # 下载内核源码(示例版本 5.4.34) wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz tar -xvf linux-5.4.34.tar.xz cd linux-5.4.34 # 配置内核(启用调试信息) make menuconfig ``` **关键配置**: `Kernel hacking` → `Compile-time checks` → ✅ **[*] Compile the kernel with debug info**(必须开启) ✅ 关闭 `Kernel address space layout randomization (KASLR)`(避免地址偏移)[^3] ```bash # 编译内核 make -j$(nproc) ``` 生成文件: - 内核镜像:`arch/x86/boot/bzImage` - 符号表:`vmlinux`(GDB 调试用) --- #### **2. 制作根文件系统(RootFS)** 使用 **BusyBox** 构建最小文件系统: ```bash # 下载并编译 BusyBox wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2 tar -xvf busybox-1.32.1.tar.bz2 cd busybox-1.32.1 make menuconfig ``` **配置**: `Settings` → ✅ **Build static binary (no shared libs)** ```bash make -j$(nproc) && make install ``` ```bash # 创建 RootFS 目录结构 mkdir rootfs cp -r _install/* rootfs/ cd rootfs mkdir -p dev proc sys sudo mknod dev/console c 5 1 # 创建设备节点 ``` ```bash # 创建 init 脚本(vim init) #!/bin/sh mount -t proc none /proc mount -t sysfs none /sys exec /bin/sh chmod +x init # 生成 RootFS 镜像 dd if=/dev/zero of=rootfs.img bs=1M count=100 mkfs.ext4 rootfs.img sudo mount -o loop rootfs.img /mnt sudo cp -r rootfs/* /mnt sudo umount /mnt ``` --- #### **3. 启动 QEMU 虚拟机** ```bash qemu-system-x86_64 \ -kernel arch/x86/boot/bzImage \ # 指定内核 -drive file=rootfs.img,format=raw \ # 挂载 RootFS -append "root=/dev/sda console=ttyS0 nokaslr" \ # 禁用 KASLR -nographic \ # 禁用图形界面 -S -s \ # -S: 暂停CPU;-s: 开启 GDB 端口(默认:1234) -net nic -net bridge,br=virbr0 # 可选:启用网络[^4] ``` --- #### **4. 使用 GDB 调试内核** ```bash # 新终端中加载符号表并连接 QEMU cd linux-5.4.34 gdb vmlinux ``` ```gdb (gdb) target remote :1234 # 连接 QEMU (gdb) b start_kernel # 在初始化函数设断点 (gdb) c # 继续执行 ``` **常用命令**: - `bt`:查看调用栈 - `list`:显示源码 - `next`/`step`:单步调试 - `p variable`:打印变量值(注意寄存器优化问题[^5]) --- #### **调试模块(Kernel Module)** 1. 编译模块时添加 `-g` 选项保留调试符号 2. 在 QEMU 中加载模块后,GDB 执行: ```gdb (gdb) add-symbol-file module.ko 0xffffffffc0000000 # 地址通过 lsmod 查看 (gdb) b module_func # 在模块函数设断点 ``` --- #### 关键注意事项 1. **调试信息**:确保内核编译开启 `CONFIG_DEBUG_INFO=y` 2. **KASLR**:启动参数必须包含 `nokaslr`,否则断点地址失效 3. **寄存器变量**:GDB 打印变量时可能显示寄存器值(非实际内存值),需结合代码分析[^5] 4. **版本匹配**:QEMU、GCC、GDB 版本需兼容(推荐 GDB ≥10.1[^3]) > 通过以上步骤,即可实现断点跟踪、变量监视等内核级调试操作。 --- ### 相关问题 1. **如何解决 GDB 调试时变量值显示异常的问题?** (提示:寄存器优化导致的伪变量问题[^5]) 2. **在 QEMU 中如何配置共享文件夹以便传输内核模块?** 3. **如何调试 Linux 内核启动过程中的内存管理错误?** 4. **使用 KGDB 调试实体机和 QEMU 调试有何区别?** 5. **如何捕获并调试内核的 OOPS(空指针异常)错误?** [^1]: Linux内核调试环境搭建及start_kernel实验 [^2]: Linux内核分析(二)--qemu搭建kernel调试环境 [^3]: 利用QEMU+GDB搭建Linux内核调试环境 [^4]: ubuntu20.04 搭建kernel调试环境第七篇--gdb调试module [^5]: ubuntu20.04 搭建kernel调试环境第八篇gdb调试技巧
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值