Skip to content

Commit a0d8083

Browse files
kvanheesnickalcock
authored andcommitted
dtrace: sdt provider core components
This implements the core (linked-in) machinery needed for SDT tracepoints: - generate empty stub function calls __dtrace_probe_* for each probe point and perf-event probe point, and record their section-relative offset in tables in special symbols in the output; calls to is-enabling probes (conditionals of the form if (DTRACE_FOO_ENABLED(probe-name))) are translated as well - similarly record the names and types of arguments to probes in special sections - parse both of these at load time, and substitute in nops over the top of the stub functions, remembering their locations: is-enabled probes get 0-returns patched over the top - on probe enabling, patch invalid-operation traps over the top of those stub functions; handle these by calling the probe, then return as if the trap had never happened The provider module itself is added in 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 2c4261a commit a0d8083

31 files changed

+2494
-22
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,9 @@ all.config
135135

136136
# Kdevelop4
137137
*.kdev4
138+
139+
#
140+
# Generated DTrace SDT files
141+
#
142+
*.sdtinfo.c
143+
*.sdtstub.S

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,7 @@ clean: $(clean-dirs)
16781678
-o -name '*.ko.*' -o -name '*.dtb' -o -name '*.dtb.S' \
16791679
-o -name '*.dwo' -o -name '*.lst' \
16801680
-o -name '*.su' \
1681+
-o -name '*.sdtinfo.c' -o -name '*.sdtstub.S' \
16811682
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
16821683
-o -name '*.lex.c' -o -name '*.tab.[ch]' \
16831684
-o -name '*.asn1.[ch]' \
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+
* Dynamic Tracing for Linux - SDT Implementation defines
4+
*
5+
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
/*
19+
* Note: The contents of this file are private to the implementation of the
20+
* DTrace subsystem and are subject to change at any time without notice.
21+
*/
22+
23+
#ifndef _X86_64_SDT_ARCH_H
24+
#define _X86_64_SDT_ARCH_H
25+
26+
#define SDT_AFRAMES 4
27+
28+
#endif /* _X86_64_SDT_ARCH_H */

arch/x86/include/asm/dtrace_arch.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,22 @@
1212

1313
typedef uint8_t asm_instr_t;
1414

15+
#define ASM_CALL_SIZE 5
16+
1517
typedef int (*prov_exit_f)(void);
1618

1719
/*
1820
* Structure to hold DTrace specific information about modules (including the
1921
* core kernel module). Note that each module (and the main kernel) already
20-
* has one field that relates to probing:
22+
* has three fields that relate to probing:
23+
* - sdt_probes: description of SDT probes in the module
24+
* - sdt_probec: number of SDT probes in the module
2125
* - pdata: pointer to a dtrace_module struct (for DTrace)
2226
*/
2327
typedef struct dtrace_module {
2428
int enabled_cnt;
29+
size_t sdt_probe_cnt;
30+
size_t fbt_probe_cnt;
2531
prov_exit_f prov_exit; /* Called with module_mutex held */
2632
} dtrace_module_t;
2733

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
/* Copyright (C) 2016 Oracle, Inc. */
4+
5+
#ifndef _X86_DTRACE_SDT_ARCH_H
6+
#define _X86_DTRACE_SDT_ARCH_H
7+
8+
#define __DTRACE_SDT_ISENABLED_PROTO void
9+
#define __DTRACE_SDT_ISENABLED_ARGS
10+
11+
#endif /* _X86_DTRACE_SDT_ARCH_H */

arch/x86/include/asm/dtrace_util.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,24 @@
66
#ifndef _X86_DTRACE_UTIL_H
77
#define _X86_DTRACE_UTIL_H
88

9+
#define DTRACE_INVOP_NOPS 0x0f /* 5-byte NOP sequence */
10+
#define DTRACE_INVOP_MOV_RSP_RBP 0x48 /* mov %rsp, %rbp = 48 89 e5 */
11+
#define DTRACE_INVOP_PUSH_BP 0x55 /* push %rbp = 55 */
12+
#define DTRACE_INVOP_NOP 0x90 /* nop = 90 */
13+
#define DTRACE_INVOP_LEAVE 0xc9 /* leave = c9 */
14+
#define DTRACE_INVOP_RET 0xc3 /* ret = c3 */
15+
916
#ifndef __ASSEMBLY__
1017

1118
#include <asm/dtrace_arch.h>
1219
#include <asm/ptrace.h>
1320

21+
extern int dtrace_invop_add(uint8_t (*func)(struct pt_regs *));
22+
extern void dtrace_invop_remove(uint8_t (*func)(struct pt_regs *));
23+
24+
extern void dtrace_invop_enable(asm_instr_t *, asm_instr_t);
25+
extern void dtrace_invop_disable(asm_instr_t *, asm_instr_t);
26+
1427
#endif
1528

1629
#endif /* _X86_DTRACE_UTIL_H */

arch/x86/include/asm/spinlock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/compiler.h>
1010
#include <asm/paravirt.h>
1111
#include <asm/bitops.h>
12+
#include <linux/sdt.h>
1213

1314
/*
1415
* Your basic SMP spinlocks, allowing only a single CPU anywhere

arch/x86/include/asm/text-patching.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
1818
#define __parainstructions_end NULL
1919
#endif
2020

21+
extern void add_nops(void *insns, unsigned int len);
2122
extern void *text_poke_early(void *addr, const void *opcode, size_t len);
2223

2324
/*

arch/x86/kernel/alternative.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ void __init arch_init_ideal_nops(void)
249249
}
250250

251251
/* Use this to add nops to a buffer, then text_poke the whole buffer. */
252-
static void __init_or_module add_nops(void *insns, unsigned int len)
252+
void __init_or_module add_nops(void *insns, unsigned int len)
253253
{
254254
while (len > 0) {
255255
unsigned int noplen = len;

arch/x86/kernel/dtrace_sdt.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* FILE: dtrace_sdt.c
4+
* DESCRIPTION: Dynamic Tracing: SDT registration code (arch-specific)
5+
*
6+
* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
7+
*/
8+
9+
#include <linux/kernel.h>
10+
#include <linux/memory.h>
11+
#include <linux/module.h>
12+
#include <linux/dtrace_os.h>
13+
#include <linux/sdt.h>
14+
#include <linux/slab.h>
15+
#include <linux/vmalloc.h>
16+
#include <asm/nmi.h>
17+
#include <asm/nops.h>
18+
#include <asm/dtrace_arch.h>
19+
#include <asm/text-patching.h>
20+
21+
static uint8_t nops[ASM_CALL_SIZE];
22+
static uint8_t movs[ASM_CALL_SIZE];
23+
24+
#define DT_OP_REX_RAX 0x48
25+
#define DT_OP_XOR_EAX_0 0x33
26+
#define DT_OP_XOR_EAX_1 0xc0
27+
28+
/* This code is based on apply_alternatives and text_poke_early. It needs to
29+
* run before SMP is initialized in order to avoid SMP problems with patching
30+
* code that might be accessed on another CPU.
31+
*/
32+
void __init_or_module dtrace_sdt_nop_multi(asm_instr_t **addrs,
33+
int *is_enabled, int cnt)
34+
{
35+
int i;
36+
asm_instr_t *addr;
37+
unsigned long flags;
38+
39+
stop_nmi();
40+
local_irq_save(flags);
41+
42+
for (i = 0; i < cnt; i++) {
43+
addr = addrs[i];
44+
if (likely(!is_enabled[i]))
45+
memcpy(addr, nops, sizeof(nops));
46+
else
47+
memcpy(addr, movs, sizeof(movs));
48+
}
49+
50+
sync_core();
51+
local_irq_restore(flags);
52+
restart_nmi();
53+
}
54+
55+
void __init dtrace_sdt_init_arch(void)
56+
{
57+
/*
58+
* A little unusual, but potentially necessary. While we could use a
59+
* single NOP sequence of length ASM_CALL_SIZE, we need to consider the
60+
* fact that when a SDT probe point is enabled, a single invalid opcode
61+
* is written on the first byte of this NOP sequence. By using a
62+
* sequence of a 1-byte NOP, followed by a (ASM_CALL_SIZE - 1) byte NOP
63+
* sequence, we play it pretty safe.
64+
*/
65+
add_nops(nops, 1);
66+
add_nops(nops + 1, ASM_CALL_SIZE - 1);
67+
68+
/*
69+
* Is-enabled probe points contain an "xor %rax, %rax" when disabled.
70+
*/
71+
movs[0] = DT_OP_REX_RAX;
72+
movs[1] = DT_OP_XOR_EAX_0;
73+
movs[2] = DT_OP_XOR_EAX_1;
74+
add_nops(movs + 3, ASM_CALL_SIZE - 3);
75+
}

0 commit comments

Comments
 (0)