-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathsystemtap.rs
130 lines (123 loc) · 5.08 KB
/
systemtap.rs
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
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! SystemTap static probes
//!
//! This is a mechanism for developers to provide static annotations for
//! meaningful points in code, with arguments that indicate some relevant
//! state. Such locations may be probed by SystemTap `process.mark("name")`,
//! and GDB can also locate them with `info probes` and `break -probe name`.
//!
//! The impact on code generation is designed to be minimal: just a single
//! `NOP` placeholder is added inline for instrumentation, and ELF notes
//! contain metadata to name the probe and describe the location of its
//! arguments.
//!
//! # Links:
//!
//! * https://sourceware.org/systemtap/man/stapprobes.3stap.html#lbAO (see `process.mark`)
//! * https://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
//! * https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
//! * https://sourceware.org/gdb/onlinedocs/gdb/Static-Probe-Points.html
//
// DEVELOPER NOTES
//
// Arguments are currently type-casted as isize for the supposed maximum
// register size, whereas SystemTap's long is i64 no matter the architecture.
// However, if we could figure out types here, they could be annotated more
// specifically, for example an argstr of "4@$0 -2@$1" indicates u32 and i16
// respectively. Any pointer would be fine too, like *c_char, simply 4@ or 8@
// for target_word_size.
//
// The macros in sdt.h don't know types either, so they split each argument
// into two asm inputs, roughly:
// asm("[...]"
// ".asciz \"%n[_SDT_S0]@%[_SDT_A0]\""
// "[...]"
// : :
// [_SDT_S0] "n" ((_SDT_ARGSIGNED (x) ? 1 : -1) * (int) sizeof (x)),
// [_SDT_A0] "nor" (x)
// );
// where _SDT_ARGSIGNED is a macro using gcc builtins, so it's still resolved a
// compile time, and %n makes it a raw literal rather than an asm number.
//
// This might be a possible direction for Rust SDT to follow. For LLVM
// InlineAsm, the string would look like "${0:n}@$1", but we need the size/sign
// for that first input, and that must be a numeric constant no matter what
// optimization level we're at. With Rust RFC 2850 `asm!`, it might be possible
// to use positional `{}@{}` with a `const` operand for the size, but calling
// things like `mem::size_of::<T>()` is still hard when we don't know `T`.
//
// FIXME semaphores - SDT can define a short* that debuggers will increment when
// they attach, and decrement on detach. Thus a probe_enabled!(provider,name)
// could return if that value != 0, to be used similarly to log_enabled!(). We
// could even be clever and skip argument evaluation altogether, the same way
// that log!() checks log_enabled!() first.
//
#[doc(hidden)]
#[macro_export]
macro_rules! platform_probe(
($provider:ident, $name:ident,)
=> ($crate::sdt_asm!($provider, $name,));
($provider:ident, $name:ident, $arg1:expr, $($arg:expr,)*)
=> ($crate::sdt_asm!($provider, $name,
"-{size}@{}", $arg1, $(" -{size}@{}", $arg,)*));
);
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
#[doc(hidden)]
#[macro_export]
macro_rules! sdt_asm(
($provider:ident, $name:ident, $($argstr:literal, $arg:expr,)*)
=> (unsafe {
$crate::_sdt_asm!(options(att_syntax), $provider, $name, $($argstr, $arg,)*);
}));
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
#[doc(hidden)]
#[macro_export]
macro_rules! sdt_asm(
($provider:ident, $name:ident, $($argstr:literal, $arg:expr,)*)
=> (unsafe {
$crate::_sdt_asm!(options(), $provider, $name, $($argstr, $arg,)*);
}));
// Since we can't #include <sys/sdt.h>, we have to reinvent it...
// but once you take out the C/C++ type handling, there's not a lot to it.
#[doc(hidden)]
#[macro_export]
macro_rules! _sdt_asm(
(options ($($opt:ident),*), $provider:ident, $name:ident, $($argstr:literal, $arg:expr,)*) => (
asm!(concat!(r#"
990: nop
.pushsection .note.stapsdt,"?","note"
.balign 4
.4byte 992f-991f, 994f-993f, 3
991: .asciz "stapsdt"
992: .balign 4
993: .{size}byte 990b
.{size}byte _.stapsdt.base
.{size}byte 0 // FIXME set semaphore address
.asciz ""#, stringify!($provider), r#""
.asciz ""#, stringify!($name), r#""
.asciz ""#, $($argstr,)* r#""
994: .balign 4
.popsection
.ifndef _.stapsdt.base
.pushsection .stapsdt.base,"aG","progbits",.stapsdt.base,comdat
.weak _.stapsdt.base
.hidden _.stapsdt.base
_.stapsdt.base: .space 1
.size _.stapsdt.base, 1
.popsection
.endif
"#
),
$(in(reg) (($arg) as isize) ,)*
size = const core::mem::size_of::<isize>(),
options(readonly, nostack, preserves_flags, $($opt),*),
)
));