x86 kgdb deug调试分析

本文主要是收集,以下文章写得很好,我二次整理一下。

如果要手动livedb.

1.  call kdbg_arch_late()

2. kgd_set_hw_break(addr,8,1);

3. kgdb_correct_hw_break();// enable bp to cpu regs

-------------------------------分割线---------------------------------------

为KGDB 增加watchpoint断点支持 on x86

为KGDB 增加watchpoint断点支持 on x86 – linux kgdb gdb debug

前言

前面我们在《gdb 和 watchpoint》 文章
里讨论了在gdb的watchpoint,这次我们来讨论下如何让kgdb也支持watchpoint特性。

KGDB 相当于一个gdb server,只是这个server是跑在内核里面。所以KGDB支持watchpoint实现和
gdb server的实现如出一辙,即通过GDB远程串行协议里的Stop-Reply-Packets来传达
watchpoint信息给gdb,让gdb知道那个watchpoint击中了。

其运行的大致流程为:

1
2
3
4
5
6
7
8
9
10
11
A:using gdb to set a watchpoint B:send out a set watchpoint protocol packet to kgdb from gdbC:kgdb receive/parse the protocol packetD:kgdb set a watchpoint hardware breakpoint on kernelE:Once kernel hit a watchpoint breakpoint, kgdb will collect the watchpoint breakpoint info, fill them to a Stop-Reply-Packets with watchpoint format, and send out to gdb

1: 设置watchpoint 断点 in kgdb

在gdb敲入watch命令后,会将发送一个设置watchpoint的数据包给kgdb,kgdb收该数据包后就执行设置断点动作.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 (gdb) watch xxx  (假设我们要监视断点地址为 xxx)gdb发送数据包"Z2,xxx,4" 给kgdbkgdb 收到协议数据包后,调用gdb_cmd_break()(kernel/debug/gdbstub.c)来解析设置断点协议数据gdb_cmd_break()
------------------------------------------
parsing  "Z2,xxx,4"
--> 'Z'      设置断点
--> '2'      断点类型为write watchpoint
--> 'xxx'  断点地址为 xxx
--> '4'      断点长度为 4
--------------------------------------------> arch_kgdb_ops.set_hw_breakpoint(xxx, 4, BP_WRITE_WATCHPOINT)
--> kgdb_set_hw_break(xxx, 4, BP_WRITE_WATCHPOINT) (arch/x86/kernel/kgdb.c)这个函数完成了将断点信息加入到breakinfo[HBP_NUM]数组里和设置其enabled标志为1,真正的断点使能是在kgdb退出,让系统正常运行时,调用kgdb_correct_hw_break()函数来每个cpu上使能硬件断点.

2: watchpoint触发捕获

watchpoint 断点隶属于硬件断点,所以我们先来谈谈硬件断点的触发的整个流程和细节。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
硬件断点的触发后,会产生一个调试异常,因此会进入do_debug异常的
处理程序(arch/x86/kernel/traps.c).do_debug() {unsigned long dr6;
get_debugreg(dr6, 6); //保持dr6寄存器值到dr6变量/* DR6 may or may not be cleared by the CPU */
set_debugreg(0, 6); //手动清除dr6寄存器//通过notify_die通知链告诉大家"debug"异常发生了,同时把dr6寄存器值作为参数传递出去。
notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,SIGTRAP)
}

如果kgdb处于早期调试模式(那时候Hardware Breakpoint Layer还没初始化),则是由kgdb自己处理
DIE_DEBUG的notify通知,如果是普通模式,即硬件断点管理都是从Hardware Breakpoint Layer获取的,
则是由Hardware Breakpoint Layer处理,然后通过回调函数kgdb_hw_overflow_handler()进入kgdb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Hardware Breakpoint Layer处理流程:static struct notifier_block hw_breakpoint_exceptions_nb = {.notifier_call = hw_breakpoint_exceptions_notify,/* we need to be notified first */.priority = 0x7fffffff
};
register_die_notifier(&hw_breakpoint_exceptions_nb);触发硬件断点:
do_debug() -- notify_die(DIE_DEBUG)->
arch/x86/kernel/hw_breakpoint.c
hw_breakpoint_exceptions_notify() -> 
hw_breakpoint_handler() {
for (i = 0; i < HBP_NUM; ++i) {if (likely(!(dr6 & (DR_TRAP0 << i))))continue;perf_bp_event(bp, args->regs); -->perf_swevent_overflow(event)->event->overflow_handler(event, nmi, data, regs);-->kgdb_hw_overflow_handler(). 这里最终跑到kgdb的代码里了.
}/* end of for()*/
}

3: watchpoint 断点信息获取

kgdb只需要知道是哪个watchpoint断点被踩中了,并把它的地址传递给gdb就可以了。

如果kgdb处于早期调试模式,则可以挨个判断dr6寄存器值的bit位来看哪个watchpoint击中了。
但是普通模式的Hardware Breakpoint Layer回调函数并没有传递dr6值给我们,不过还好,它传
递struct perf_event的event对象给我们,通过这个对象,我们可以得到发生硬断点的地址,然后
根据地址和kgdb里保存的硬断点数组对比,相同的,则是踩中的断点..

1
2
3
4
5
6
7
8
9
static void kgdb_hw_overflow_handler(struct perf_event *event, int nmi,struct perf_sample_data *data, struct pt_regs *regs) {for (i = 0; i < HBP_NUM; i++) {if (!breakinfo[i].enabled)continue;if (breakinfo[i].addr == event->attr.bp_addr) //查找和判断踩中断点信息break;}
}

在得到是哪个breakinfo[i]被触发后,在查看下breakinfo[i].type,如果是
X86_BREAKPOINT_WRITE/X86_BREAKPOINT_RW 就可以认定是watchpoint断点了,
而断点地址则保存在breakinfo[i].addr.

4: 填充Stop-Reply-Packets来通知gdb踩中watchpoint断点了
根据watchpoint断点的类型,返回给gdb的Stop-Reply-Packets可以有如下格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type = breakinfo[i].type;
addr = breakinfo[i].addr;switch (type) {case KST_READ_WATCHPOINT:ptr += strlen(strcpy(ptr, "rwatch:"));break;case KST_ACCESS_WATCHPOINT:ptr += strlen(strcpy(ptr, "awatch:"));break;case KST_WRITE_WATCHPOINT:ptr += strlen(strcpy(ptr, "watch:"));break;}ptr += kgdb_long2hex(addr, ptr);*ptr++ = ';';

具体packgets包格式,可以阅读 Stop-Reply-Packets

5: test watchpoint support on x86

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
After gdb connect successly to kgdb, setting a watchpoint
at softlockup_thresh address.(gdb) watch softlockup_threshThen change the watchdog_thresh value to 24 on target:
# echo "24" > /proc/sys/kernel/watchdog_threshThen the gdb will stop and show:
----------------------------------------------------------
Old value = 60
New value = 24
0xffffffff810481f2 in do_proc_dointvec_minmax_conv (negp=0xffff88066cbb9e17,
lvalp=0xffffffff8190e718, valp=0xffffffff8190e718, write=<value optimized out>,
data=0xffff88066cbb9e68) at kernel/sysctl.c:2408
2408			*valp = val;
(gdb)
----------------------------------------------------------Change the watchdog_thresh value to 24 on target again:
# echo "24" > /proc/sys/kernel/watchdog_threshAs the previous watchdog_thresh value is 24, thus gdb will not stop..

6: 扩展阅读

更多有关kgdb和Hardware Breakpoint Layer的内容,可阅读:《抓虫日记之 kgdb 和 删除硬断点 》
更多有关x86硬件调试寄存器信息,可阅读:《x86 调试寄存器》

x86 调试寄存器 – linux kgdb gdb debug

英文官方介绍《Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide》第16章-- DEBUGGING, PROFILING BRANCHES AND TIME-STAMP COUNTER

本文内容转载自
==============================
调试寄存器(DRx)理论与实践
By Hume/冷雨飘心 Humewen@21cn.com.
==============================

有8个调试寄存器供处理器操作,其中有2个被保留,所以真正可用的寄存器只有6个Dr0,Dr1,Dr2,Dr3,Dr6和Dr7。这些寄存器全是32位,如下图所示:

Dr0~3 用于设置硬件断点,即在调试器中经常使用的bpm断点,由于只有4个断点寄存器,所以最多只能设置4个bpm断点。Dr7是一些控制位,用于控制断点的方式,Dr6用于显示是哪些引起断点的原因,如果是Dr0~3或单步(EFLAGS的TF)或由于GD置位时访问调试寄存器引起1号调试陷阱的话,则相应设置对应的位。下面对Dr6和Dr7的对应位做一些详细介绍:

调试控制寄存器Dr7:

位0 L0和位1 G0:用于控制Dr0是全局断点还是局部断点,如果G0置位则是全局断点,L0置位则是局部断点。
G1L1~G3L3用于控制D1~Dr3,其功能同上。

LEN0:占两个位,开始于位15,用于控制Dr0的断点长度,可能取值:
00 1字节
01 2字节
10 保留
11 4字节
RWE0:从第17位开始,占两个位,控制Dr0的断点是读、写还是执行断点或是I/O端口断点:
00 只执行
01 写入数据断点
10 I/O端口断点(只用于pentium+,需设置CR4的DE位)
11 读或写数据断点
RWE1~3,LEN1~3分别用于控制Dr1~3的断点方式,含义如上。

还有一个GD位:用于保护DRx,如果GD位为1,则对Drx的任何访问都会导致进入1号调试陷阱。即IDT的对应入口,这样可以保证调试器在必要的时候完全控制Drx。

调试状态寄存器Dr6:

该寄存器用于表示进入陷阱1的原因,各个位的含义如下:
B0~B3,如果其中任何一个位置位,则表示是相应的Dr0~3断点引发的调试陷阱。但还需注意的是,有时候不管GiLi如何设置,只要是遇到Drx指定的断点,总会设置Bi,如果看到多个Bi置位,则可以通过GiLi的情况判断究竟是哪个Dr寄存器引发的调试陷阱。
BD置位表示是GD位置位情况下访问调试寄存器引发的陷阱。
BT置位表示是因为TS置位即任务切换时TSS中TS位置1时切到第二个任务时第一条指令时引发的。
BS置位表示是单步中断引发的断点。。。。即EFLAGS的TF置位时引发的调试陷阱。

注意I/O端口断点是586+以上CPU才有的功能,受CR4的DE位的控制,DE为1才有效。(DE是CR4的第3位)。

其它相关链接

【总结】调试寄存器 原理与使用:DR0-DR7

DDD的博客:抓虫日记之 kgdb 和 删除硬断点 - 哲思

为避免硬/软断点影响kgdb,在kgdb主程序kgdb_cpu_enter运行过程中,所有的断点是被disable的。
对于硬件断点来说,它会显示的调用kgdb_disable_hw_debug()来disable所有的硬件断点,
在kgdb离开时,调用kgdb_correct_hw_break()来使能/增加需要激活的硬件断点。

A: 前言

自从Prasad Krishnan兄(也许该叫大叔)引入Hardware Breakpoint统一管理机制后,
结束了各个内核模块中对Hardware Breakpoint处理各自为政的状态,一统Hardware
Breakpoint的天下.

KGDB也无例外,为了对别人负责,也需要迁移到Hardware Breakpoint Layer, 其实
kgdb对使用Hardware Breakpoint Layer是很不爽的。为避免大家心里暗怨我瞎说,
特举例如下:

 1: 使用Hardware Breakpoint Layer,增加了kgdb对系统的依赖性,这潜在的影响kgdb的稳定性。2: 当kgdb用于早期调试时(如系统初始化阶段),Hardware Breakpoint Layer有可能还没有初始化,那时候还是得kgdb自己来管理硬件断点。从这个角度来说kgdb支持Hardware Breakpoint Layer确实比较鸡肋。3: Hardware Breakpoint Layer依赖notifier_chain来实现的,有时候kgdb会避免使用notifier_chain的(这样就可以单步调试notifier的相关代码),一旦使用了HardwareBreakpoint Layer,就不能调试notifier的相关代码时,应该kgdb依赖它,kgdb是不能自己调自己的。

迫于像大家看齐的压力,kgdb还是忍痛接受了Hardware Breakpoint Layer,反正
Hardware Breakpoint Layer还是有一个好处的,就是not evil,不会破坏别人的硬件断点设置,
这样别人不会来抱怨你冲掉他们的硬断点设置。

为了让kgdb这个怪物支持Hardware Breakpoint Layer,Hardware Breakpoint Layer
还是给予了一定的协助的,如提供一些无锁操作函数等等.如为原来有锁的release_bp_slot提供
一个无锁的dbg_release_bp_slot.
kgdb由于使用了NMI这个强大的DD,如果调用一些持锁的函数,基本有概率会”无理由”的把你
给锁住,哭都不知道找谁去。同样,在Jason大牛的一番艰苦奋战下,kgdb基本把Hardware
Breakpoint Layer给摆平了.

B: 问题和现象

但在某天某时某分(秒就算了),我发现在对硬断点增/减多次操作后,在操作就再也不成功了。
经过多次重启机器的麻木实验后,发现规律如下:
前四次是肯定可以成功,而后面的操作是肯定不可以成功。

而四正好是X86的硬件断点最大数,也就是Hardware Breakpoint Layer定义的最大操作数。
从这个表象上看,很可能是删除断点的时候没有删掉,于是开始dig kgdb硬断点相关代码.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/82153.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Automatic1111在本地PC上运行SDXL 1.0

这是我们部署Stable Diffusion的第三篇文章了&#xff0c;前两篇文章都详细介绍了Automatic1111的stable-diffusion-webui的安装&#xff0c;这次主要介绍如何使用SDXL 1.0模型。 获取项目 在本地获取Automatic1111’s WebUI项目&#xff0c;下载完成后应该是这个样子的 下载检…

(十二)大数据实战——hadoop集群之HDFS高可用自动故障转移

前言 本节内容主要介绍一下hadoop集群下实现HDFS高可用的自动故障转移&#xff0c;HDFS高可用的自动故障转移主要通过zookeeper实现故障的监控和主节点的切换。自动故障转移为 HDFS 部署增加了两个新组件&#xff1a;ZooKeeper 和 ZKFailoverController &#xff08;ZKFC&…

Jmeter(六) - 从入门到精通 - 建立数据库测试计划(详解教程)

1.简介 在实际工作中&#xff0c;我们经常会听到数据库的性能和稳定性等等&#xff0c;这些有时候也需要测试工程师去评估和测试&#xff0c;因此这篇文章主要介绍了jmeter连接和创建数据库测试计划的过程,在文中通过示例和代码非常详细地介绍给大家&#xff0c;希望对各位小伙…

干货分享|Elsevier投稿进度查询功能正式上线,随时获取投稿状态!

想必广大科研学者们都经历过每天登录系统查看投稿进度的煎熬过程&#xff0c;为了方便广大科研人随时获取投稿状态&#xff0c;2023年8月&#xff0c;Elsevier【微信端投稿进度查询功能】正式上线&#xff01; 无论你是通讯作者还是共同作者&#xff0c;只需一次查询&#xff…

实现vuex数据持久化处理

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 前言&#xff1a; 方案一 localStorage 介绍 值 示例 JSON.stringify() 介绍 语法 参数 返…

AVS3:跨多通道预测PMC

前面的文章中介绍了TSCPM&#xff0c;它是AVS3中用于intra模式的跨通道预测技术&#xff0c;它利用线性模型根据亮度重建像素预测色度像素&#xff0c; 跨通道预测技术用于去除不同通道间的冗余信息&#xff0c;TSCPM可以去除Y-Cb、Y-Cr通道间的冗余&#xff0c;然而却忽略了…

【css】组合器

组合器是解释选择器之间关系的某种机制。在简单选择器器之间&#xff0c;可以包含一个组合器&#xff0c;从而实现简单选择器难以达到的效果。 CSS 中有四种组合器&#xff1a; 后代选择器 (空格)&#xff1a;匹配属于指定元素后代的所有元素&#xff0c;示例&#xff1a;div …

CTF流量题解http1.pcapng

使用Wireshark工具打开流量文件http1.pcapng&#xff0c;如下图所示。 在过滤检索栏输入http&#xff0c;wireshark自动进行过滤。 选中其中一条记录后&#xff0c;wireshark 下方显示若干信息。 Frame 81: 925 bytes on wire (7400 bits), 925 bytes captured (7400 bits) …

【设计模式——学习笔记】23种设计模式——中介者模式Observer(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入案例一普通实现中介者模式 案例二 介绍基础介绍登场角色尚硅谷 《图解设计模式》 案例实现案例一&#xff1a;智能家庭类图实现 案例二&#xff1a;登录页面逻辑实现说明类图实现 总结文章说明 案例引入 案例一 普通实现 在租房过程中&#xff0c;客户可能…

【LeetCode每日一题】——219.存在重复元素II

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 哈希表 二【题目难度】 简单 三【题目编号】 219.存在重复元素II 四【题目描述】 给你一个…

mysql之存储过程

目录 一、mysql之存储过程的相关知识 1&#xff09;存储过程的概念 2&#xff09;存储过程的优点 二、存储过程的管理 1&#xff09;创建存储过程 基本格式&#xff1a; 2&#xff09;调用存储过程 格式&#xff1a; call 存储过程名称 3&#xff09;查看存储过程 查…

在windows中使用parLapply函数执行并行计算

目录 1-lapply()函数介绍&#xff1a; 例子1&#xff1a; 例子2&#xff1a; 例子3&#xff1a; 2-在Windows使用并行计算&#xff0c;使用parLapply()函数 2.1-并行计算的准备阶段&#xff1a; 2.2-parLapply()函数介绍 2.3-使用parLapply()函数编写执行并行计算 2.4-…

Sentinel整合Spring Cloud Gateway、Zuul详解

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。 Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块&#xff0c;此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑&#xff1a; GatewayFlowRule&#xff1a;网关限流规则…

Python AI 绘画

Python AI 绘画 本文我们将为大家介绍如何基于一些开源的库来搭建一套自己的 AI 作图工具。 需要使用的开源库为 Stable Diffusion web UI&#xff0c;它是基于 Gradio 库的 Stable Diffusion 浏览器界面 Stable Diffusion web UI GitHub 地址&#xff1a;GitHub - AUTOMATI…

棒球电影产业建设·野球1号位

棒球电影产业建设 1. 引言 棒球电影产业在美国和全球的历史发展概述 自20世纪初&#xff0c;棒球电影产业在美国开始起步&#xff0c;以一种富有创意的方式将体育和娱乐结合起来&#xff0c;开创了一种全新的娱乐形式。这些电影为观众提供了一个了解棒球运动的独特视角&#…

力扣279.完全平方数(动态规划)

class Solution { public:int numSquares(int n) {vector<int> f(n 1);for (int i 1; i < n; i) {int minn INT_MAX;for (int j 1; j * j < i; j) {minn min(minn, f[i - j * j]); //上一次的 & 当前数可以找到一个新的更大的平方}f[i] minn 1; }…

Godot4 C# vscode开发环境搭建

用vscode搭建Godot4 C# 开发环境搭建 软件Godot配置vscode配置结果参考 软件 Godot .Net版本: 下载链接vscode :自行下载.netcore7&#xff1a;.netcore6可能也行vscode插件&#xff1a; Godot配置 1.配置文件用VSCode打开 2.生成C#项目 项目–>工具–>C#->Creat…

WPF实战项目十一(API篇):待办事项功能api接口

1、新建ToDoController.cs继承基础控制器BaseApiController&#xff0c;但是一般业务代码不写在控制器内&#xff0c;业务代码写在Service&#xff0c;先新建统一返回值格式ApiResponse.cs&#xff1a; public class ApiResponse{public ApiResponse(bool status, string mess…

【Fegin技术专题】「原生态」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(中)

你可以使用 Jersey 和 CXF 这些来写一个 Rest 或 SOAP 服务的java客服端。 你也可以直接使用 Apache HttpClient 来实现。但是 Feign 的目的是尽量的减少资源和代码来实现和 HTTP API 的连接。 *通过自定义的编码解码器以及错误处理&#xff0c;你可以编写任何基于文本的 HTT…

python数据分析 期末测验,python数据分析基础题库

大家好&#xff0c;小编为大家解答python数据分析选择题题目的问题。很多人还不知道python数据分析题目和答案&#xff0c;现在让我们一起来看看吧&#xff01; 自测试卷 5 一、选择题 1 &#xff0e;下面关于 RFM 模型说法正确的是&#xff08; &#xff09;。 A &#xff0e;…