testhrarr.c
考虑调试中给出的内核模块- 观察 Linux 内核中的变量(内存地址)变化,并在变化时打印堆栈跟踪?- Stack Overflow,它跟踪对内存位置的写访问。
现在,我正在尝试跟踪读/写访问,这是通过更改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: error inserting './testhrarr.ko': -1 Invalid parameters”而失败。有谁知道为什么?
无论如何,这里的问题是,一旦我用 观察读/写访问HW_BREAKPOINT_W | HW_BREAKPOINT_R
,我无法在我的处理程序中判断我得到的堆栈跟踪是由于读访问还是写访问。我经历过:
- include/linux/perf_event.h
perf_event_attr
中的结构 - 结构
hw_perf_event
包括/linux/perf_event.h - include/linux/hw_breakpoint.h用于
HW_BREAKPOINT_*
枚举定义
...而且我在任何地方都找不到从硬件断点处理程序中检索的显式技术,无论是触发的读访问还是写访问。我只在kernel/trace/trace_ksym.c中找到了一些东西,但trace_ksym
已被弃用(甚至在我的 2.6.38 中都没有),而且它只是 reads 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
is just HW_BREAKPOINT_W
,则只报告三个(然后会像上面的代码hw.interrupts == 1
一样错误地报告)。_R
那么,如果我只是颠倒 and 的含义_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
断点;因此,如果我们尝试仅设置 for HW_BREAKPOINT_R
,则该过程将无法返回 -EINVAL。
所以,我想,我主要需要 X86 的答案,虽然如果有一个通用的可移植机制来确定读/写访问,我宁愿知道......