考虑debugging - Watch a variable (memory address) change in Linux kernel, and print stack trace when it changes? - Stack Overflow中给出的内核模块testhrarr.c
,它跟踪对内存位置的写访问。
现在,我正在尝试跟踪读/写访问,我通过更改testhrarr_init
函数中的这一行来完成:
attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
这里的第一个问题是:在我的平台上(Linux内核2.6.38); HW_BREAKPOINT_W
关于它自己的工作,HW_BREAKPOINT_W | HW_BREAKPOINT_R
用于读/写工作 - 但是只尝试使用HW_BREAKPOINT_R
进行读取访问不起作用;当我在/var/log/syslog
中得到“断点注册失败”时,insmod
失败并出现“insmod:错误插入'./testhrarr.ko': - 无效参数”。有谁知道为什么?
无论如何,这里的问题是,一旦我用HW_BREAKPOINT_W | HW_BREAKPOINT_R
观察读/写访问,我无法告诉我的处理程序我得到的堆栈跟踪是由于读取还是写入访问。我经历过:
perf_event_attr
hw_perf_event
include/linux/perf_event.h HW_BREAKPOINT_*
枚举定义
...我找不到任何从hw断点处理程序检索的显式技术,无论是读取还是写入访问。我只在kernel/trace/trace_ksym.c中找到了一些内容,但trace_ksym
已被弃用(甚至在我的2.6.38中找不到),此外它只是读取attr.bp_type
,这是我们自己在内核模块。
所以,经过一些暴力破解后,我意识到hw_perf_event->interrupts
可能包含这些信息;所以我将处理程序回调修改为:
static void sample_hbp_handler(struct perf_event *bp,
struct perf_sample_data *data,
struct pt_regs *regs)
{
struct perf_event_attr attr = bp->attr;
struct hw_perf_event hw = bp->hw;
char hwirep[8];
//it looks like printing %llu, data->type here causes segfault/oops when `cat` runs?
// apparently, hw.interrupts changes depending on read/write access (1 or 2)
// when only HW_BREAKPOINT_W, getting hw.interrupts == 1 always;
// only HW_BREAKPOINT_R - fails for me
// when both, hw.interrupts is either 1 or 2
// defined in include/linux/hw_breakpoint.h:
// HW_BREAKPOINT_R = 1, HW_BREAKPOINT_W = 2,
if (hw.interrupts == HW_BREAKPOINT_R) {
strcpy(hwirep, "_R");
} else if (hw.interrupts == HW_BREAKPOINT_W) {
strcpy(hwirep, "_W");
} else {
strcpy(hwirep, "__");
}
printk(KERN_INFO "+--- %s value is accessed (.bp_type %d, .type %d, state %d htype %d hwi %llu / %s ) ---+\n", ksym_name, attr.bp_type, attr.type, hw.state, hw.info.type, hw.interrupts, hwirep);
dump_stack();
printk(KERN_INFO "|___ Dump stack from sample_hbp_handler ___|\n");
}
......这似乎有点奏效;正如我在syslog
中得到以下内容:
$ grep "testhrarr_arr_first value" /var/log/syslog
kernel: [ 200.887620] +--- testhrarr_arr_first value is accessed (.bp_type 3, .type 5, state 0 htype 131 hwi 1 / _R ) ---+
kernel: [ 200.892163] +--- testhrarr_arr_first value is accessed (.bp_type 3, .type 5, state 0 htype 131 hwi 1 / _R ) ---+
kernel: [ 200.892634] +--- testhrarr_arr_first value is accessed (.bp_type 3, .type 5, state 0 htype 131 hwi 2 / _W ) ---+
kernel: [ 200.912192] +--- testhrarr_arr_first value is accessed (.bp_type 3, .type 5, state 0 htype 131 hwi 1 / _R ) ---+
kernel: [ 200.912713] +--- testhrarr_arr_first value is accessed (.bp_type 3, .type 5, state 0 htype 131 hwi 2 / _W ) ---+
kernel: [ 200.932138] +--- testhrarr_arr_first value is accessed (.bp_type 3, .type 5, state 0 htype 131 hwi 1 / _R ) ---+
...但是,如果attr.bp_type
只是HW_BREAKPOINT_W
,则只会报告三个hw.interrupts == 1
(然后使用上面的代码将其错误地报告为_R
。
那么,如果我只是颠倒_R
和_W
的含义,我可能得到的东西与我想要发生的东西相符 - 但这显然是黑暗中的一个镜头,因为我不知道hw_perf_event->interrupts
应该代表什么。
那么 - 有没有人知道确定访问硬件监视的内存位置的“方向”(读或写)的正确方法?
编辑:我的第一个子问题的答案:对于我的架构,x86,有这段代码:
http://lxr.free-electrons.com/source/arch/x86/kernel/hw_breakpoint.c?v=2.6.38#L252
static int arch_build_bp_info(struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
info->address = bp->attr.bp_addr;
/* Type */
switch (bp->attr.bp_type) {
case HW_BREAKPOINT_W:
info->type = X86_BREAKPOINT_WRITE;
break;
case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
info->type = X86_BREAKPOINT_RW;
break;
case HW_BREAKPOINT_X:
info->type = X86_BREAKPOINT_EXECUTE;
// ...
default:
return -EINVAL;
}
...
}
...明确指出X86有_WRITE
或_RW
个断点;因此,如果我们尝试仅为HW_BREAKPOINT_R
设置,则该过程将无法返回-EINVAL。
所以,我想,我在这里主要针对X86需要答案,尽管如果有一个通用的便携式机制来确定读/写访问,我宁愿知道......