1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
| int__kprobes kprobe_exceptions_notify(structnotifier_block *self,
unsigned longval,void*data)
{
structdie_args *args =data;
intret =NOTIFY_DONE;
if(args->regs &&user_mode_vm(args->regs))
returnret;
switch(val){
caseDIE_INT3:
/*对于kprobe,进入kprobe_handle*/
if(kprobe_handler(args->regs))
ret =NOTIFY_STOP;
break;
caseDIE_DEBUG:
if(post_kprobe_handler(args->regs)){
/*
* Reset the BS bit in dr6 (pointed by args->err) to
* denote completion of processing
*/
(*(unsigned long*)ERR_PTR(args->err))&=~DR_STEP;
ret =NOTIFY_STOP;
}
break;
caseDIE_GPF:
/*
* To be potentially processing a kprobe fault and to
* trust the result from kprobe_running(), we have
* be non-preemptible.
*/
if(!preemptible()&&kprobe_running()&&
kprobe_fault_handler(args->regs,args->trapnr))
ret =NOTIFY_STOP;
break;
default:
break;
}
returnret;
}
staticint__kprobes kprobe_handler(structpt_regs *regs)
{
kprobe_opcode_t *addr;
structkprobe *p;
structkprobe_ctlblk *kcb;
/*对于int 3中断,其被Intel定义为Trap,那么异常发生时EIP寄存器内指向的为异常指令的后一条指令*/
addr =(kprobe_opcode_t *)(regs->ip -sizeof(kprobe_opcode_t));
/*
* We don't want to be preempted for the entire
* duration of kprobe processing. We conditionally
* re-enable preemption at the end of this function,
* and also in reenter_kprobe() and setup_singlestep().
*/
preempt_disable();
kcb =get_kprobe_ctlblk();
/*获取addr对应的kprobe*/
p =get_kprobe(addr);
if(p){
/*如果异常的进入是由kprobe导致,则进入reenter_kprobe(jprobe需要,到时候分析)*/
if(kprobe_running()){
if(reenter_kprobe(p,regs,kcb))
return1;
}else{
set_current_kprobe(p,regs,kcb);
kcb->kprobe_status =KPROBE_HIT_ACTIVE;
/*
* If we have no pre-handler or it returned 0, we
* continue with normal processing. If we have a
* pre-handler and it returned non-zero, it prepped
* for calling the break_handler below on re-entry
* for jprobe processing, so get out doing nothing
* more here.
*/
/*执行在此地址上挂载的pre_handle函数*/
if(!p->pre_handler ||!p->pre_handler(p,regs))
/*设置单步调试模式,为post_handle函数的执行做准备*/
setup_singlestep(p,regs,kcb,0);
return1;
}
}elseif(*addr !=BREAKPOINT_INSTRUCTION){
/*
* The breakpoint instruction was removed right
* after we hit it. Another cpu has removed
* either a probepoint or a debugger breakpoint
* at this address. In either case, no further
* handling of this interrupt is appropriate.
* Back up over the (now missing) int3 and run
* the original instruction.
*/
regs->ip =(unsigned long)addr;
preempt_enable_no_resched();
return1;
}elseif(kprobe_running()){
p =__this_cpu_read(current_kprobe);
if(p->break_handler &&p->break_handler(p,regs)){
setup_singlestep(p,regs,kcb,0);
return1;
}
}/* else: not a kprobe fault; let the kernel handle it */
preempt_enable_no_resched();
return0;
}
staticvoid__kprobes setup_singlestep(structkprobe *p,structpt_regs *regs,
structkprobe_ctlblk *kcb,intreenter)
{
if(setup_detour_execution(p,regs,reenter))
return;
#if!defined(CONFIG_PREEMPT)
if(p->ainsn.boostable ==1 &&!p->post_handler){
/* Boost up -- we can execute copied instructions directly */
if(!reenter)
reset_current_kprobe();
/*
* Reentering boosted probe doesn't reset current_kprobe,
* nor set current_kprobe, because it doesn't use single
* stepping.
*/
regs->ip =(unsigned long)p->ainsn.insn;
preempt_enable_no_resched();
return;
}
#endif
/*jprobe*/
if(reenter){
save_previous_kprobe(kcb);
set_current_kprobe(p,regs,kcb);
kcb->kprobe_status =KPROBE_REENTER;
}else
kcb->kprobe_status =KPROBE_HIT_SS;
/* Prepare real single stepping */
/*准备单步模式,设置EFLAGS的TF标志位,清楚IF标志位(禁止中断)*/
clear_btf();
regs->flags|=X86_EFLAGS_TF;
regs->flags&=~X86_EFLAGS_IF;
/* single step inline if the instruction is an int3 */
if(p->opcode ==BREAKPOINT_INSTRUCTION)
regs->ip =(unsigned long)p->addr;
else
/*设置异常返回的指令为保存的被探测点的指令*/
regs->ip =(unsigned long)p->ainsn.insn;
}
|