Skip to content

Commit 25f11bb

Browse files
kvanheesnickalcock
authored andcommitted
dtrace: core and x86
This implements DTrace's core kernel (linked-in) components, including platform-dependent portions for x86. (Most of this machinery is not used until the next commit.) Signed-off-by: Nick Alcock <[email protected]> Signed-off-by: Kris Van Hees <[email protected]> Signed-off-by: Tomas Jedlicka <[email protected]> Signed-off-by: Eugene Loh <[email protected]> Signed-off-by: David Mc Lean <[email protected]> Signed-off-by: Vincent Lim <[email protected]>
1 parent 3c5af76 commit 25f11bb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+6975
-4
lines changed

Makefile

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -962,22 +962,25 @@ core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
962962

963963
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
964964
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
965-
$(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))
965+
$(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y) \
966+
$(dtrace-y) $(dtrace-m)))
966967

967968
vmlinux-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \
968-
$(init-) $(core-) $(drivers-) $(net-) $(libs-) $(virt-))))
969+
$(init-) $(core-) $(drivers-) $(net-) $(libs-) $(virt-) \
970+
$(dtrace-))))
969971

970972
init-y := $(patsubst %/, %/built-in.a, $(init-y))
971973
core-y := $(patsubst %/, %/built-in.a, $(core-y))
972974
drivers-y := $(patsubst %/, %/built-in.a, $(drivers-y))
975+
dtrace-y := $(patsubst %/, %/built-in.a, $(dtrace-y))
973976
net-y := $(patsubst %/, %/built-in.a, $(net-y))
974977
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
975978
libs-y2 := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))
976979
virt-y := $(patsubst %/, %/built-in.a, $(virt-y))
977980

978981
# Externally visible symbols (used by link-vmlinux.sh)
979982
export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
980-
export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y2) $(drivers-y) $(net-y) $(virt-y)
983+
export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y2) $(drivers-y) $(net-y) $(virt-y) $(dtrace-y)
981984
export KBUILD_VMLINUX_LIBS := $(libs-y1)
982985
export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
983986
export LDFLAGS_vmlinux

arch/x86/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ config PGTABLE_LEVELS
354354
default 3 if X86_PAE
355355
default 2
356356

357+
config ARCH_SUPPORTS_DTRACE
358+
def_bool y if X86_64
359+
357360
config CC_HAS_SANE_STACKPROTECTOR
358361
bool
359362
default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC)) if 64BIT

arch/x86/include/asm/dtrace_arch.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
/*
4+
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
5+
*/
6+
7+
#ifndef _X86_DTRACE_ARCH_H
8+
#define _X86_DTRACE_ARCH_H
9+
10+
/* Number of arguments stored inside the mstate. */
11+
#define DTRACE_MSTATE_ARGS_MAX 6
12+
13+
typedef uint8_t asm_instr_t;
14+
15+
typedef int (*prov_exit_f)(void);
16+
17+
/*
18+
* Structure to hold DTrace specific information about modules (including the
19+
* core kernel module). Note that each module (and the main kernel) already
20+
* has one field that relates to probing:
21+
* - pdata: pointer to a dtrace_module struct (for DTrace)
22+
*/
23+
typedef struct dtrace_module {
24+
int enabled_cnt;
25+
prov_exit_f prov_exit; /* Called with module_mutex held */
26+
} dtrace_module_t;
27+
28+
#endif /* _X86_DTRACE_ARCH_H */

arch/x86/include/asm/dtrace_cpuinfo.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
/* Copyright (C) 2013-2014 Oracle, Inc. */
4+
5+
#ifndef _ASM_X86_DTRACE_CPUINFO_H_
6+
#define _ASM_X86_DTRACE_CPUINFO_H_
7+
8+
#include <asm/processor.h>
9+
10+
typedef struct cpuinfo_x86 cpuinfo_arch_t;
11+
12+
#define dtrace_cpuinfo_chip(ci) ((ci)->phys_proc_id)
13+
14+
#endif /* _ASM_X86_DTRACE_CPUINFO_H_ */

arch/x86/include/asm/dtrace_util.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
4+
*/
5+
6+
#ifndef _X86_DTRACE_UTIL_H
7+
#define _X86_DTRACE_UTIL_H
8+
9+
#ifndef __ASSEMBLY__
10+
11+
#include <asm/dtrace_arch.h>
12+
#include <asm/ptrace.h>
13+
14+
#endif
15+
16+
#endif /* _X86_DTRACE_UTIL_H */

arch/x86/kernel/dtrace_util.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* FILE: dtrace_util.c
4+
* DESCRIPTION: Dynamic Tracing: Architecture utility functions
5+
*
6+
* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
7+
*/
8+
9+
#include <linux/dtrace_cpu.h>
10+
#include <linux/dtrace_os.h>
11+
#include <linux/dtrace_task_impl.h>
12+
#include <linux/kdebug.h>
13+
#include <linux/mm.h>
14+
#include <linux/module.h>
15+
#include <linux/memory.h>
16+
#include <linux/notifier.h>
17+
#include <linux/ptrace.h>
18+
#include <linux/sched.h>
19+
#include <linux/slab.h>
20+
#include <linux/uaccess.h>
21+
#include <linux/sched/task_stack.h>
22+
#include <asm/insn.h>
23+
#include <asm/pgtable.h>
24+
#include <asm/ptrace.h>
25+
#include <asm/text-patching.h>
26+
#include <asm/dtrace_arch.h>
27+
#include <asm/dtrace_util.h>
28+
29+
int dtrace_instr_size(const asm_instr_t *addr)
30+
{
31+
struct insn insn;
32+
33+
kernel_insn_init(&insn, addr, MAX_INSN_SIZE);
34+
insn_get_length(&insn);
35+
36+
return insn_complete(&insn) ? insn.length : -1;
37+
}
38+
EXPORT_SYMBOL(dtrace_instr_size);
39+
40+
/*
41+
* Move the instruction pointer forward to the next instruction, effectiely
42+
* skipping the current one.
43+
*/
44+
static void dtrace_skip_instruction(struct pt_regs *regs)
45+
{
46+
int delta;
47+
48+
delta = dtrace_instr_size((asm_instr_t *)regs->ip);
49+
BUG_ON(delta <= 0);
50+
51+
regs->ip += delta;
52+
}
53+
54+
void dtrace_handle_badaddr(struct pt_regs *regs)
55+
{
56+
unsigned long addr = read_cr2();
57+
58+
DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
59+
this_cpu_core->cpuc_dtrace_illval = addr;
60+
61+
dtrace_skip_instruction(regs);
62+
}
63+
64+
/*
65+
* Trap notification handler.
66+
*/
67+
int dtrace_die_notifier(struct notifier_block *nb, unsigned long val,
68+
void *args)
69+
{
70+
struct die_args *dargs = args;
71+
72+
switch (val) {
73+
case DIE_PAGE_FAULT: {
74+
if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT))
75+
return NOTIFY_DONE;
76+
77+
dtrace_handle_badaddr(dargs->regs);
78+
79+
return NOTIFY_OK | NOTIFY_STOP_MASK;
80+
}
81+
case DIE_GPF: {
82+
if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT))
83+
return NOTIFY_DONE;
84+
85+
dtrace_handle_badaddr(dargs->regs);
86+
87+
return NOTIFY_OK | NOTIFY_STOP_MASK;
88+
}
89+
default:
90+
return NOTIFY_DONE;
91+
}
92+
}
93+
94+
static inline int dtrace_bad_address(void *addr)
95+
{
96+
unsigned long dummy;
97+
98+
return probe_kernel_address((unsigned long *)addr, dummy);
99+
}
100+
101+
static int dtrace_user_addr_is_exec(uintptr_t addr)
102+
{
103+
struct mm_struct *mm = current->mm;
104+
pgd_t *pgd;
105+
106+
#if CONFIG_PGTABLE_LEVELS > 3
107+
p4d_t *p4d;
108+
#endif
109+
110+
pud_t *pud;
111+
pmd_t *pmd;
112+
pte_t *pte;
113+
unsigned long flags;
114+
int ret = 0;
115+
116+
if (mm == NULL)
117+
return 0;
118+
119+
addr &= PAGE_MASK;
120+
121+
local_irq_save(flags);
122+
123+
pgd = pgd_offset(mm, addr);
124+
if (dtrace_bad_address(pgd))
125+
goto out;
126+
if (pgd_none(*pgd) || !pgd_present(*pgd))
127+
goto out;
128+
129+
#if CONFIG_PGTABLE_LEVELS > 3
130+
p4d = p4d_offset(pgd, addr);
131+
if (dtrace_bad_address(p4d))
132+
goto out;
133+
if (p4d_none(*p4d) || !p4d_present(*p4d))
134+
goto out;
135+
136+
pud = pud_offset(p4d, addr);
137+
#else
138+
pud = pud_offset(pgd, addr);
139+
#endif
140+
141+
if (dtrace_bad_address(pud))
142+
goto out;
143+
if (pud_none(*pud) || !pud_present(*pud))
144+
goto out;
145+
if (unlikely(pud_large(*pud))) {
146+
pte = (pte_t *)pud;
147+
if (dtrace_bad_address(pte))
148+
goto out;
149+
150+
ret = pte_exec(*pte);
151+
goto out;
152+
}
153+
154+
pmd = pmd_offset(pud, addr);
155+
if (dtrace_bad_address(pmd))
156+
goto out;
157+
if (pmd_none(*pmd))
158+
goto out;
159+
if (unlikely(pmd_large(*pmd) || !pmd_present(*pmd))) {
160+
pte = (pte_t *)pmd;
161+
if (dtrace_bad_address(pte))
162+
goto out;
163+
164+
ret = pte_exec(*pte);
165+
goto out;
166+
}
167+
168+
pte = pte_offset_map(pmd, addr);
169+
if (dtrace_bad_address(pte))
170+
goto out;
171+
if (pte_protnone(*pte))
172+
goto out;
173+
if ((pte_flags(*pte) & (_PAGE_PRESENT|_PAGE_USER|_PAGE_SPECIAL)) !=
174+
(_PAGE_PRESENT|_PAGE_USER))
175+
goto out;
176+
177+
ret = pte_exec(*pte);
178+
179+
out:
180+
local_irq_restore(flags);
181+
182+
return ret;
183+
}
184+
185+
void dtrace_user_stacktrace(stacktrace_state_t *st)
186+
{
187+
struct pt_regs *regs = current_pt_regs();
188+
uint64_t *pcs = st->pcs;
189+
int limit = st->limit;
190+
unsigned long *bos;
191+
unsigned long *sp = (unsigned long *)user_stack_pointer(regs);
192+
int ret;
193+
194+
if (!user_mode(regs))
195+
goto out;
196+
197+
if (current->dt_task == NULL)
198+
goto out;
199+
200+
bos = current->dt_task->dt_ustack;
201+
202+
st->depth = 1;
203+
if (pcs)
204+
*pcs++ = (uint64_t)instruction_pointer(regs);
205+
limit--;
206+
207+
if (!limit)
208+
goto out;
209+
210+
while (sp <= bos && limit) {
211+
unsigned long pc;
212+
213+
pagefault_disable();
214+
ret = __copy_from_user_inatomic(&pc, sp, sizeof(pc));
215+
pagefault_enable();
216+
217+
if (ret)
218+
break;
219+
220+
if (dtrace_user_addr_is_exec(pc)) {
221+
if (pcs)
222+
*pcs++ = pc;
223+
limit--;
224+
st->depth++;
225+
}
226+
227+
sp++;
228+
}
229+
230+
out:
231+
if (pcs) {
232+
while (limit--)
233+
*pcs++ = 0;
234+
}
235+
}
236+
237+
void dtrace_mod_pdata_init(dtrace_module_t *pdata)
238+
{
239+
}
240+
241+
void dtrace_mod_pdata_cleanup(dtrace_module_t *pdata)
242+
{
243+
}

0 commit comments

Comments
 (0)