Linux(三) makefile与gdb调试

makefile

mkefile文件中定义了一系列的规则来指定,哪些文件需要线编译,哪些后编译,哪些需要重新编译,甚至进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

mkefile带来的好处就是“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大提高了软件开发的效率。

make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如visual c++的nmake,Linux下GNU的make,可见,makefile都成为了一种在工程方面的编译方法。
makefile文件中会使用gcc编译器对源代码进行编译,最终生成可执行文件或者库文件。
makefile文件的命令:makefile或者Makefile

makefile的工作原理

若想生成目标,检查规则中的所有的依赖条件是否都存在:
在这里插入图片描述

如果有的依赖条件不存在

向下搜索规则,看是否有生成该依赖条件的规则:
如果有规则用来生成该依赖条件,则执行规则中的命令生成依赖条件
如果没有规则用来生成该依赖文件,则报错

如果所有依赖条件都存在

检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任何一个被更新,则目标必须更新(检查的规则是哪个时间段哪个更新)

  • 如果目标的时间>依赖时间,不更新
  • 如果目标的时间<依赖时间,则更新

makefile的基本规则

makefile由一组规则组成,规则如下:

目标: 依赖
(tab)命令
基本规则三要素
  • 目标:要生成的目标文件
  • 依赖: 目标文件由哪些文件生成
  • 命令: 通过执行该命令由依赖文件生成目标

mkefile不同版本写法

现有main.c,fun1.c,fun2.c ,head.h三个文件
在这里插入图片描述

第一个版本

vi makefile
内容:

main:main.c fun1.c fun2.c
	gcc -o main main.c fun1.c fun2.c
第二个版本
 main:main.o fun1.o fun2.o
     gcc -o main main.o fun1.o fun2.o
 main.o:main.c
     gcc -c main.c -I./
 fun1.o:fun1.c
     gcc -c fun1.c
 fun2.o:fun2.c
    gcc -c fun2.c

在这里插入图片描述
分步写,如果中间量更改,可以减少重新编译的内容

第三个版本

makefile的变量

在makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使makefile易于维护,修改起来简单
makefile有三种类型的变量

  • 普通变量
  • 自带变量
  • 自动变量
普通变量
  • 变量定义直接用 =
  • 使用变量值用 $(变量名)
自带变量

makefile中也提供了一些变量(变量名大写)供用户直接使用,我们可以直接对其进行赋值

CC = gcc #arm-linux-gcc
CPPFLAGS:C预处理的选项有 -I
CFLAGS: C编译器的选项 -Wall -g -c
LDFLAGS: 链接器选项 -L -l
自动变量
  • $@:表示规则中的目标
  • $<:表示规则中的第一个条件
  • $^:表示规则中所有条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项
    自动变量只能在规则中的命令中使用
模式规则

至少在规则的目标定义中要包含%,%表示一个或多个,在依赖条件中同样可以使用%,依赖条件中的%取决于其目标
根据makefile的变量进行替换
在这里插入图片描述
在这里插入图片描述
利用变量进行更改,可以减少代码量

第四个版本

makefile函数
wildcard 查找指定目录下的指定类型的文件
src=$(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src
patsubst 匹配替换
obj=$(patsubst %.c,%.o,$(src)) //把src变量里面所有后缀为.c的文件替换成.o

在makefile中所有的函数都是有返回值的
在这里插入图片描述

第五个版本

makefile的清理操作

用途:清楚编译生成的中间.o文件和最终目标文件
make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令,解决方案:
伪目标声明:
.PHONY:clean
声明目标伪伪目标之后,makefile将不会检查该目标是否存在或者该目标是否需要更新

clean命令中的特殊符号
  • “-”此条命令出错,make也会继续执行后续的命令
  • “@”不显示命令本身,只显示结果。
其它
  • make 默认执行第一个出现的目标,可通过make dest 指定要执行的目标
  • make -f:-f执行一个makefile文件名称,使用make执行的指定的makefile:如make -f xxx(xxx是一个makefile文件,可以随意取名)
    在这里插入图片描述
    在这里插入图片描述

gdb调试

gdb介绍

GDB(GNU Debugger)是GCC的调试工具。其功能强大
GDB主要功能:

  • 启动程序,可以按照你的自定义的要求随心所欲的运行程序
  • 可让被调试的程序在你的自定义的要求随心所欲的运行程序
  • 当程序被停止时,可以检查此时你的程序中所发生的事
  • 动态的改变你程序的执行环境

生成调试信息

一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们需要把调试信息加入到可执行文件。使用编译器(cc/gcc/g++)的-g参数可以做到这一点。

gcc -g hello.c -o hello

如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。

启动gdb

启动gdb : gdb program
program也就是你的执行文件,一般在当前目录下
设置运行参数
set args 可指定运行时参数。(如:set args 10 20 30 40 50)

显示源代码

GDB可以打印出所有调试程序的源代码,当然,在程序编译时一定要加上-g参数。
当程序停下来以后,可以通过list命令来打印程序的源代码
用法如下:

  • list linenum :打印第linenum行的上下文内容
  • list function:显示函数名为function的函数的源程序
  • list:显示当前行后面的源程序
  • list -:显示当前文件开始处的源程序
  • list file:linenum:显示file文件下第linenum行
  • list file:function:显示file文件的函数名为function的函数的源程序
    一般打印当前行的上5行和下5行,默认是10行
    使用下面的命令可以设置一次显示源程序的函数
  • set listsize count :设置一次显示源代码的函数
  • show listsize:查看当前listsize的设置

设置断点

简单断点-当前文件

break 设置断点,可以简写为b

  • b 10 意思是在源程序的第10行设置断点
  • b func 在func函数入口处设置断点

多文件设置断点–其他文件

  • b filename:linenum 在源文件为filename的linenum行设置断点
  • b filename:function 在源文件filename的function函数的入口处设置断点

查询所有断点

info b == info break == i b

条件断点

为断点设置一个条件,使用关键字if

b xxx.c:n if intValue ==5
如果intValue的值等于5,在xxx.c文件第n行中设置断点

维护断点

delete [range…]

删除指定的断点

  • delete 删除所有的断点
  • delete num 删除断点为num的断点
  • delete num1 num3 删除不连续的断点 num1 num3
  • delete n-m 删除连续的断点,删除 n-m的断点
disable[range…]也可以简写为dis [range…]

指定断点无效,不会删除断点

enable[range…]也可以简写为ena[range…]

指定断点有效,对应解开disable设置的无效断点

调试代码

  • run 运行程序,可简写为r
  • next 单步跟踪,函数调用当做一条简单语句执行,可简写为n
  • step 单步跟踪,函数调用进入被调用函数体内,可简写为s
  • finish 退出进入的函数,如果出不去,可能是函数体中的循环有断点,可以将其删除或设置为无效
  • untile 在一个循环体内单步跟踪,这个命令可以运行程序,直到退出循环体,可简写为u
  • continue 继续运行程序,可简写为c(如果有断点,则调到下一个断点处)

查看变量的值

查看运行时变量的值

print 打印变量、字符串、表达式等的值,可简写为p

p count -----打印count的值
p &count ----打印count的地址

自动显示变量的值

可以设置一些自动显示的变量,当程序停住是,或在单步追踪时,这些变量会自动显示
相关的GDB命令是display

  • display 变量名 设置自动显示
  • info display --查看display设置的自动显示的信息
  • undisplay num (info display时显示的编号)删除自动显示
  • delete display dnums —删除自动显示,dums意味着自动显示的编号,如果要同时删除,用空格分隔,如果删除连续的,可以用-
  • disable display dnums 设置dnums无效
  • enable display dnums 设置dnums有效,与display相反

查看修改变量的值

ptype xxx —查看变量名为xxx的类型
p xxx ----打印变量名为xxx的值

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: gdb是一个强大的调试工具,可以用于调试Linux内核。使用gdb调试Linux内核需要以下步骤: 1. 编译内核时添加调试信息 在编译内核时需要添加调试信息,可以通过在Makefile中添加以下选项来实现: CONFIG_DEBUG_INFO=y CONFIG_DEBUG_KERNEL=y 2. 启动内核调试 在启动内核时需要添加调试选项,可以通过在grub或者lilo中添加以下选项来实现: debug debug earlyprintk=serial,ttyS0,115200 3. 连接gdb 使用gdb连接内核需要使用kgdb插件,可以通过以下命令加载kgdb插件: modprobe kgdb 然后使用以下命令连接gdb: gdb vmlinux (gdb) target remote /dev/ttyS0 4. 使用gdb调试 连接成功后,可以使用gdb进行调试,例如: (gdb) b start_kernel (gdb) c 这将在内核启动时设置断点,并继续执行内核。当内核执行到断点时,gdb将停止执行并等待命令。 以上是使用gdb调试Linux内核的基本步骤,具体调试方法和命令可以参考gdb文档和Linux内核调试文档。 ### 回答2: gdb是一款功能强大的调试器,在日常的编程开发中得到了广泛应用。然而,gdb调试Linux内核时与调试用户态应用程序时有所不同。调试内核需要使用gdb的特殊功能来处理调试内核的问题。在下面的几个方面中,我将解释如何使用gdb来调试Linux内核。 1. 准备gdb环境 首先需要将gdb环境设置为可以使用内核符号。在编译内核时,需要在Makefile中添加CONFIG_DEBUG_INFO和CONFIG_DEBUG_KERNEL选项,以支持调试信息。此外,还需要安装所需的内核符号,然后通过"sudo sysctl -w kernel.yama.ptrace_scope=0"以解决防止调试器附加的安全机制问题。 2. 加载内核映像 通过gdb来加载内核映像。使用gdb命令"file vmlinux"来加载内核映像,其中vmlinux是含有调试符号的内核镜像文件。 3. 内核断点调试 可以使用gdb设置内核断点,以调试内核时确定内核程序执行过程中的问题。使用gdb命令"b <function>"设置函数断点,而使用"b * <address>"设置指定地址的断点。 4. 调试内核panic 当内核执行时发生错误时,系统会进入panic状态。如果需要调试内核panic,可以使用gdb命令"handle SIGTRAP noprint pass"来设置中断处理。使用"monitor halt"或直接ctrl+c可以停止内核,查看是什么出问题了,并且使用"cont"命令让内核继续运行。 5. 查看内核堆栈 可以使用gdb命令"bt"来查看内核的堆栈,以确定调试内核时的问题。在通过gdb调试内核处理内核问题时,内核堆栈非常有用。 总的来说,使用gdb调试Linux内核需要更多的操作方式和技巧,但是如果熟练掌握gdb的某些功能和命令,并且了解内核基本结构和运行机制,就可以高效地调试内核出现的问题。 ### 回答3: GDB(GNU调试器)是一个强大的调试工具,也可以用来调试Linux内核。但是,与调试应用程序或用户空间程序相比,内核调试可能会更加复杂。下面是关于如何使用GDB调试Linux内核的一些指南和步骤。 1.编译内核 为了调试内核,首先需要编译内核并安装它。在编译内核时,需要启用符号表。使用如下命令: $ make menuconfig 在Kernel hacking中设置Debug kernel,这将启用符号表的编译。然后使用命令“make”编译内核并安装它。 2.配置调试环境 在内核启动时,启用调试合适的调试器非常重要。例如,可以使用串线调试器而不是控制台输出,因为调试信息可能无法立即打印到控制台。可以通过UART控制台或JTAG调试器进行调试,这通常比控制台输出更可靠。 3.使用GDB连接到内核 使用GDB的第一步是启动GDB,同时指定内核映像文件作为第一个参数。例如,如果内核映像文件为”vmlinuz”,可以使用如下命令连接GDB到内核: $ gdb vmlinuz 然后,需要设置GDB的默认连接地址: add-symbol-file /path/to/kernel/vmlinux 0xADDRESS 这里的ADDRESS 应该是编译内核时已知的地址。可以在内核映像文件的/System.map文件中找到地址信息。 4.使用GDB调试 在连接GDB到内核后,可以使用GDB来单步执行内核代码或设置断点。可以使用GDB的“step”命令来进入下一个函数调用,并使用“next”命令来执行下一行代码。还可以使用“break”命令设置断点,以捕获特定的行动或事件。 也可以在调试内核时使用一些GDB的调试命令,例如:“watch”命令用于设置监视点,以监视变量的值,而不必停止调试器。可以使用“info” 命令,以获取关于调试目标状态的信息。 总之,调试Linux内核需要仔细的计划和准备。在内核源代码中随时插入代码并编译并不是一个高效的方法。使用GDB可以更轻松地捕获和解决内核的问题。通过使用GDB,可以提高软件开发的效率,并确保Linux内核的稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值