* [lttng-dev] [PATCH lttng-modules v5 0/5] Extract payload from polling syscalls
@ 2016-04-23 0:16 Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 1/5] Add ctf_integer_bitfield_type Julien Desfossez
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Julien Desfossez @ 2016-04-23 0:16 UTC (permalink / raw)
Patch serie to extract the payload of the polling system calls on x86 and ARM
(32 and 64-bit). The concerned system calls are select, pselect6, poll, ppoll,
epoll_ctl, epoll_wait, epoll_pwait.
Changes from v4:
- Use GFP_ATOMIC memory for dynamic allocation (because we cannot sleep in TP)
- Limit the allocated memory to one page
- Set an overflow flag if we cannot allocate enough memory
- Fix endianness problem for select
- Bugfix from v4 review
Changes from v3:
- Use dynamic allocation for select
- Bugfix from v3 review
- Cleanup epoll_wait error handling
Changes from v2:
- Make sure all user-controlled data is handled safely in the kernel
- Allocate memory instead of using the stack for arbitrarily large data
- Only extract the standard event flags and output the raw event value as hex
- Various bugfixes from v2
Julien Desfossez (5):
Add ctf_integer_bitfield_type
Extract the FD sets in select and pselect6
Extract the FDs and flags from poll and ppoll
Extract the payload for epoll_ctl
Extract the payload of epoll_wait/epoll_pwait
.../syscalls/headers/syscalls_pointers_override.h | 1243 ++++++++++++++++++++
probes/lttng-events-write.h | 8 +
2 files changed, 1251 insertions(+)
--
1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 1/5] Add ctf_integer_bitfield_type
2016-04-23 0:16 [lttng-dev] [PATCH lttng-modules v5 0/5] Extract payload from polling syscalls Julien Desfossez
@ 2016-04-23 0:16 ` Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6 Julien Desfossez
` (3 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Julien Desfossez @ 2016-04-23 0:16 UTC (permalink / raw)
Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
Acked-by: Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
---
probes/lttng-events-write.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/probes/lttng-events-write.h b/probes/lttng-events-write.h
index 5db66eb..87741a1 100644
--- a/probes/lttng-events-write.h
+++ b/probes/lttng-events-write.h
@@ -22,6 +22,10 @@
#define ctf_integer(_type, _item, _src) \
_ctf_integer_ext(_type, _item, _src, __BYTE_ORDER, 10, 0, 0)
+#undef ctf_integer_bitfield
+#define ctf_integer_bitfield(_type, _item, _src) \
+ _ctf_integer_ext(_type, _item, _src, __LITTLE_ENDIAN, 10, 0, 0)
+
#undef ctf_integer_hex
#define ctf_integer_hex(_type, _item, _src) \
_ctf_integer_ext(_type, _item, _src, __BYTE_ORDER, 16, 0, 0)
@@ -145,6 +149,10 @@
#define ctf_integer_type(_type, _src) \
ctf_integer(_type, unused, _src)
+#undef ctf_integer_bitfield_type
+#define ctf_integer_bitfield_type(_type, _src) \
+ ctf_integer_bitfield(_type, unused, _src)
+
#undef ctf_integer_hex_type
#define ctf_integer_hex_type(_type, _src) \
ctf_integer_hex(_type, unused, _src)
--
1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6
2016-04-23 0:16 [lttng-dev] [PATCH lttng-modules v5 0/5] Extract payload from polling syscalls Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 1/5] Add ctf_integer_bitfield_type Julien Desfossez
@ 2016-04-23 0:16 ` Julien Desfossez
2016-04-25 20:42 ` Julien Desfossez
2016-04-29 18:13 ` Mathieu Desnoyers
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 3/5] Extract the FDs and flags from poll and ppoll Julien Desfossez
` (2 subsequent siblings)
4 siblings, 2 replies; 12+ messages in thread
From: Julien Desfossez @ 2016-04-23 0:16 UTC (permalink / raw)
Instead of extracting the user-space pointers of the 3 fd_set, we now
extract the bitmask of the FDs in the sets (in, out, ex) in the form of
an array of uint8_t (1024 FDs is the limit in the kernel).
In this example, we select in input FDs 5 to 19 (0xFFFF0), it returns
that one FD is ready: FD 12 (0x1000).
syscall_entry_select: {
n = 20,
_fdset_in_length = 3, fdset_in = [ [0] = 0xF0, [1] = 0xFF, [2] = 0xF ],
_fdset_out_length = 0, fdset_out = [ ],
_fdset_ex_length = 0, fdset_ex = [ ],
tvp = 0
}
syscall_exit_select: {
ret = 1,
_fdset_in_length = 3, fdset_in = [ [0] = 0x0, [1] = 0x10, [2] = 0x0 ],
_fdset_out_length = 0, fdset_out = [ ],
_fdset_ex_length = 0, fdset_ex = [ ],
tvp = 0
}
Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
---
| 510 +++++++++++++++++++++
1 file changed, 510 insertions(+)
--git a/instrumentation/syscalls/headers/syscalls_pointers_override.h b/instrumentation/syscalls/headers/syscalls_pointers_override.h
index bf5c632..ef4dc1c 100644
--- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
+++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
@@ -53,4 +53,514 @@ SC_LTTNG_TRACEPOINT_EVENT(pipe2,
)
)
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64)
+#define OVERRIDE_32_select
+#define OVERRIDE_64_select
+SC_LTTNG_TRACEPOINT_EVENT_CODE(select,
+ TP_PROTO(sc_exit(long ret,) int n, fd_set __user *inp, fd_set __user *outp,
+ fd_set __user *exp, struct timeval *tvp),
+ TP_ARGS(sc_exit(ret,) n, inp, outp, exp, tvp),
+ TP_locvar(
+ unsigned long *fds_in, *fds_out, *fds_ex;
+ unsigned long nr_bytes, nr_ulong;
+ unsigned int overflow;
+ ),
+ TP_code_pre(
+ sc_inout(
+ {
+ int err;
+
+ tp_locvar->fds_in = NULL;
+ tp_locvar->fds_out = NULL;
+ tp_locvar->fds_ex = NULL;
+
+ tp_locvar->overflow = 0;
+
+ sc_out(
+ if (ret <= 0)
+ goto error;
+ )
+
+ if (n <= 0)
+ goto error;
+
+ /* Limit atomic memory allocation to one page */
+ if (DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) > PAGE_SIZE) {
+ tp_locvar->nr_bytes = PAGE_SIZE;
+ tp_locvar->nr_ulong = PAGE_SIZE / sizeof(unsigned long);
+ /* Inform the user that we did not output everything. */
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->nr_bytes = DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE);
+ tp_locvar->nr_ulong = DIV_ROUND_UP((unsigned int) n,
+ BITS_PER_BYTE * sizeof(unsigned long));
+ }
+ /* On error or bogus input, don't copy anything. */
+ if (tp_locvar->nr_bytes > (__FD_SETSIZE / (8 * sizeof(uint8_t)))) {
+ goto error;
+ }
+
+ if (inp) {
+ tp_locvar->fds_in = kmalloc(
+ tp_locvar->nr_ulong * sizeof(unsigned long),
+ GFP_ATOMIC);
+ if (!tp_locvar->fds_in)
+ goto error;
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds_in, inp,
+ tp_locvar->nr_ulong * sizeof(unsigned long));
+ if (err != 0)
+ goto error;
+ }
+ if (outp) {
+ tp_locvar->fds_out = kmalloc(
+ tp_locvar->nr_ulong * sizeof(unsigned long),
+ GFP_ATOMIC);
+ if (!tp_locvar->fds_out)
+ goto error;
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds_out, outp,
+ tp_locvar->nr_ulong * sizeof(unsigned long));
+ if (err != 0)
+ goto error;
+ }
+ if (exp) {
+ tp_locvar->fds_ex = kmalloc(
+ tp_locvar->nr_ulong * sizeof(unsigned long),
+ GFP_ATOMIC);
+ if (!tp_locvar->fds_ex)
+ goto error;
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds_ex, exp,
+ tp_locvar->nr_ulong * sizeof(unsigned long));
+ if (err != 0)
+ goto error;
+ }
+ goto end;
+
+ error:
+ tp_locvar->nr_bytes = 0;
+ tp_locvar->nr_ulong = 0;
+ end:
+ /* bypass error: label at end of compound statement */
+ ;
+ }
+ )
+ ),
+ TP_FIELDS(
+ sc_exit(ctf_integer(long, ret, ret))
+ sc_in(ctf_integer(int, n, n))
+ sc_inout(ctf_integer(int, overflow, tp_locvar->overflow))
+ sc_inout(ctf_integer(struct timeval *, tvp, tvp))
+
+ sc_inout(
+ /* inp */
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence,
+ .u.sequence.length_type = __type_integer(
+ uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
+ .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
+ __BYTE_ORDER, 16, none),
+ ),
+ readfds,
+ ctf_custom_code(
+ unsigned int src;
+ unsigned int nr_bytes_out = 0;
+
+ if (inp) {
+ ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
+ ctf_align(uint8_t)
+ } else {
+ ctf_integer_type(uint16_t, 0)
+ ctf_align(uint8_t)
+ goto skip_inp;
+ }
+
+ for (src = 0; src < tp_locvar->nr_ulong; src++) {
+ int dst;
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+ for (dst = 0; dst < sizeof(long); dst++) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (inp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_inp;
+ }
+ }
+#else
+ for (dst = sizeof(long); dst >= 0; dst--) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (inp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_inp;
+ }
+ }
+#endif
+ }
+ skip_inp:
+ ;
+ )
+ )
+ /* outp */
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence,
+ .u.sequence.length_type = __type_integer(
+ uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
+ .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
+ __BYTE_ORDER, 16, none),
+ ),
+ writefds,
+ ctf_custom_code(
+ unsigned int src;
+ unsigned int nr_bytes_out = 0;
+
+ if (outp) {
+ ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
+ ctf_align(uint8_t)
+ } else {
+ ctf_integer_type(uint16_t, 0)
+ ctf_align(uint8_t)
+ goto skip_outp;
+ }
+
+ for (src = 0; src < tp_locvar->nr_ulong; src++) {
+ int dst;
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+ for (dst = 0; dst < sizeof(long); dst++) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (outp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_outp;
+ }
+ }
+#else
+ for (dst = sizeof(long); dst >= 0; dst--) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (outp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_outp;
+ }
+ }
+#endif
+ }
+ skip_outp:
+ ;
+ )
+ )
+ /* exp */
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence,
+ .u.sequence.length_type = __type_integer(
+ uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
+ .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
+ __BYTE_ORDER, 16, none),
+ ),
+ exceptfds,
+ ctf_custom_code(
+ unsigned int src;
+ unsigned int nr_bytes_out = 0;
+
+ if (exp) {
+ ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
+ ctf_align(uint8_t)
+ } else {
+ ctf_integer_type(uint16_t, 0)
+ ctf_align(uint8_t)
+ goto skip_exp;
+ }
+
+ for (src = 0; src < tp_locvar->nr_ulong; src++) {
+ int dst;
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+ for (dst = 0; dst < sizeof(long); dst++) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (exp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_exp;
+ }
+ }
+#else
+ for (dst = sizeof(long); dst >= 0; dst--) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (exp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_exp;
+ }
+ }
+#endif
+ }
+ skip_exp:
+ ;
+ )
+ )
+ )
+ ),
+ TP_code_post(
+ kfree(tp_locvar->fds_in);
+ kfree(tp_locvar->fds_out);
+ kfree(tp_locvar->fds_ex);
+ )
+)
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM)
+#define OVERRIDE_32_pselect6
+#define OVERRIDE_64_pselect6
+SC_LTTNG_TRACEPOINT_EVENT_CODE(pselect6,
+ TP_PROTO(sc_exit(long ret,) int n, fd_set __user * inp, fd_set __user * outp,
+ fd_set __user * exp, struct timeval * tvp, void * sig),
+ TP_ARGS(sc_exit(ret,) n, inp, outp, exp, tvp, sig),
+ TP_locvar(
+ unsigned long *fds_in, *fds_out, *fds_ex;
+ unsigned long nr_bytes, nr_ulong;
+ unsigned int overflow;
+ ),
+ TP_code_pre(
+ sc_inout(
+ {
+ int err;
+
+ tp_locvar->fds_in = NULL;
+ tp_locvar->fds_out = NULL;
+ tp_locvar->fds_ex = NULL;
+
+ tp_locvar->overflow = 0;
+
+ sc_out(
+ if (ret <= 0)
+ goto error;
+ )
+
+ if (n <= 0)
+ goto error;
+
+ /* Limit atomic memory allocation to one page */
+ if (DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) > PAGE_SIZE) {
+ tp_locvar->nr_bytes = PAGE_SIZE;
+ tp_locvar->nr_ulong = PAGE_SIZE / sizeof(unsigned long);
+ /* Inform the user that we did not output everything. */
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->nr_bytes = DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE);
+ tp_locvar->nr_ulong = DIV_ROUND_UP((unsigned int) n,
+ BITS_PER_BYTE * sizeof(unsigned long));
+ }
+ /* On error or bogus input, don't copy anything. */
+ if (tp_locvar->nr_bytes > (__FD_SETSIZE / (8 * sizeof(uint8_t)))) {
+ goto error;
+ }
+
+ if (inp) {
+ tp_locvar->fds_in = kmalloc(
+ tp_locvar->nr_ulong * sizeof(unsigned long),
+ GFP_ATOMIC);
+ if (!tp_locvar->fds_in)
+ goto error;
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds_in, inp,
+ tp_locvar->nr_ulong * sizeof(unsigned long));
+ if (err != 0)
+ goto error;
+ }
+ if (outp) {
+ tp_locvar->fds_out = kmalloc(
+ tp_locvar->nr_ulong * sizeof(unsigned long),
+ GFP_ATOMIC);
+ if (!tp_locvar->fds_out)
+ goto error;
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds_out, outp,
+ tp_locvar->nr_ulong * sizeof(unsigned long));
+ if (err != 0)
+ goto error;
+ }
+ if (exp) {
+ tp_locvar->fds_ex = kmalloc(
+ tp_locvar->nr_ulong * sizeof(unsigned long),
+ GFP_ATOMIC);
+ if (!tp_locvar->fds_ex)
+ goto error;
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds_ex, exp,
+ tp_locvar->nr_ulong * sizeof(unsigned long));
+ if (err != 0)
+ goto error;
+ }
+ goto end;
+
+ error:
+ tp_locvar->nr_bytes = 0;
+ tp_locvar->nr_ulong = 0;
+ end:
+ /* bypass error: label at end of compound statement */
+ ;
+ }
+ )
+ ),
+ TP_FIELDS(
+ sc_exit(ctf_integer(long, ret, ret))
+ sc_in(ctf_integer(int, n, n))
+ sc_in(ctf_integer(int, overflow, tp_locvar->overflow))
+ sc_inout(ctf_integer(struct timeval *, tvp, tvp))
+
+ sc_inout(
+ /* inp */
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence,
+ .u.sequence.length_type = __type_integer(
+ uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
+ .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
+ __BYTE_ORDER, 16, none),
+ ),
+ readfds,
+ ctf_custom_code(
+ unsigned int src;
+ unsigned int nr_bytes_out = 0;
+
+ if (inp) {
+ ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
+ ctf_align(uint8_t)
+ } else {
+ ctf_integer_type(uint16_t, 0)
+ ctf_align(uint8_t)
+ goto skip_inp;
+ }
+
+ for (src = 0; src < tp_locvar->nr_ulong; src++) {
+ int dst;
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+ for (dst = 0; dst < sizeof(long); dst++) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (inp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_inp;
+ }
+ }
+#else
+ for (dst = sizeof(long); dst >= 0; dst--) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (inp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_inp;
+ }
+ }
+#endif
+ }
+ skip_inp:
+ ;
+ )
+ )
+ /* outp */
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence,
+ .u.sequence.length_type = __type_integer(
+ uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
+ .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
+ __BYTE_ORDER, 16, none),
+ ),
+ writefds,
+ ctf_custom_code(
+ unsigned int src;
+ unsigned int nr_bytes_out = 0;
+
+ if (outp) {
+ ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
+ ctf_align(uint8_t)
+ } else {
+ ctf_integer_type(uint16_t, 0)
+ ctf_align(uint8_t)
+ goto skip_outp;
+ }
+
+ for (src = 0; src < tp_locvar->nr_ulong; src++) {
+ int dst;
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+ for (dst = 0; dst < sizeof(long); dst++) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (outp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_outp;
+ }
+ }
+#else
+ for (dst = sizeof(long); dst >= 0; dst--) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (outp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_outp;
+ }
+ }
+#endif
+ }
+ skip_outp:
+ ;
+ )
+ )
+ /* exp */
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence,
+ .u.sequence.length_type = __type_integer(
+ uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
+ .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
+ __BYTE_ORDER, 16, none),
+ ),
+ exceptfds,
+ ctf_custom_code(
+ unsigned int src;
+ unsigned int nr_bytes_out = 0;
+
+ if (exp) {
+ ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
+ ctf_align(uint8_t)
+ } else {
+ ctf_integer_type(uint16_t, 0)
+ ctf_align(uint8_t)
+ goto skip_exp;
+ }
+
+ for (src = 0; src < tp_locvar->nr_ulong; src++) {
+ int dst;
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+ for (dst = 0; dst < sizeof(long); dst++) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (exp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_exp;
+ }
+ }
+#else
+ for (dst = sizeof(long); dst >= 0; dst--) {
+ ctf_user_integer_type(uint8_t,
+ ((uint8_t __user *) (exp->fds_bits + src))[dst]);
+ if (++nr_bytes_out >= tp_locvar->nr_bytes) {
+ goto skip_exp;
+ }
+ }
+#endif
+ }
+ skip_exp:
+ ;
+ )
+ )
+ )
+ ),
+ TP_code_post(
+ kfree(tp_locvar->fds_in);
+ kfree(tp_locvar->fds_out);
+ kfree(tp_locvar->fds_ex);
+ )
+)
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
+
#endif /* CREATE_SYSCALL_TABLE */
--
1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 3/5] Extract the FDs and flags from poll and ppoll
2016-04-23 0:16 [lttng-dev] [PATCH lttng-modules v5 0/5] Extract payload from polling syscalls Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 1/5] Add ctf_integer_bitfield_type Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6 Julien Desfossez
@ 2016-04-23 0:16 ` Julien Desfossez
2016-04-29 18:31 ` Mathieu Desnoyers
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 4/5] Extract the payload for epoll_ctl Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 5/5] Extract the payload of epoll_wait/epoll_pwait Julien Desfossez
4 siblings, 1 reply; 12+ messages in thread
From: Julien Desfossez @ 2016-04-23 0:16 UTC (permalink / raw)
Instead of printing the pointer address of the poll set, extract all the
FDs and flags from the poll set. For now, we only output the
standardized set of events to limit the verbosity of the output, we also
extract the raw value. When we switch to CTF2 we will be able to hide
unset fields and then we will extract all the fields.
Here is an example of output with one FD:
syscall_entry_poll: {
timeout_msecs = -1, nfds = 1, fds_length = 1,
fds = [
[0] = { fd = 4, raw_events = 0x5, events = { POLLIN = 1, POLLPRI = 0,
POLLOUT = 1, POLLERR = 0, POLLHUP = 0, padding = 0 } } ]
}
syscall_exit_poll: {
ret = 1, nfds = 1, fds_length = 1,
fds = [ [0] = { fd = 4, raw_events = 0x4, events = { POLLIN = 0,
POLLPRI = 0, POLLOUT = 1, POLLERR = 0, POLLHUP = 0, padding = 0 } } ] }
Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
---
| 360 +++++++++++++++++++++
1 file changed, 360 insertions(+)
--git a/instrumentation/syscalls/headers/syscalls_pointers_override.h b/instrumentation/syscalls/headers/syscalls_pointers_override.h
index ef4dc1c..6ade85c 100644
--- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
+++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
@@ -563,4 +563,364 @@ SC_LTTNG_TRACEPOINT_EVENT_CODE(pselect6,
)
#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
+#ifndef ONCE_LTTNG_TRACE_POLL_H
+#define ONCE_LTTNG_TRACE_POLL_H
+
+#define LTTNG_POLL_NRFLAGS (POLLNVAL + 1)
+#define POLL_FLAGS_PADDING_SIZE (sizeof(uint8_t) * BITS_PER_BYTE) - \
+ ilog2(LTTNG_POLL_NRFLAGS - 1)
+
+/*
+ * Only extract the values specified by iBCS2 for now.
+ */
+static struct lttng_event_field lttng_pollfd_flag_fields[] = {
+ [ilog2(POLLIN)] = {
+ .name = "POLLIN",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ [ilog2(POLLPRI)] = {
+ .name = "POLLPRI",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ [ilog2(POLLOUT)] = {
+ .name = "POLLOUT",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ [ilog2(POLLERR)] = {
+ .name = "POLLERR",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ [ilog2(POLLHUP)] = {
+ .name = "POLLHUP",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ [ilog2(POLLNVAL)] = {
+ .name = "POLLNVAL",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ [ilog2(LTTNG_POLL_NRFLAGS)] = {
+ .name = "padding",
+ .type = __type_integer(int, POLL_FLAGS_PADDING_SIZE, 1, 0,
+ __LITTLE_ENDIAN, 10, none),
+ },
+};
+
+static struct lttng_event_field lttng_pollfd_fields[] = {
+ [0] = {
+ .name = "fd",
+ .type = __type_integer(int, 0, 0, 0, __BYTE_ORDER, 10, none),
+ },
+ [1] = {
+ .name = "raw_events",
+ .type = __type_integer(short, 0, 0, 0, __BYTE_ORDER, 16, none),
+ },
+ [2] = {
+ .name = "events",
+ .type = {
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(lttng_pollfd_flag_fields),
+ .u._struct.fields = lttng_pollfd_flag_fields,
+ }
+ },
+};
+
+static struct lttng_type lttng_pollfd_elem = {
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(lttng_pollfd_fields),
+ .u._struct.fields = lttng_pollfd_fields,
+};
+#endif /* ONCE_LTTNG_TRACE_POLL_H */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64)
+#define OVERRIDE_32_poll
+#define OVERRIDE_64_poll
+SC_LTTNG_TRACEPOINT_EVENT_CODE(poll,
+ TP_PROTO(sc_exit(long ret,) struct pollfd __user * ufds,
+ unsigned int nfds, int timeout_msecs),
+ TP_ARGS(sc_exit(ret,) ufds, nfds, timeout_msecs),
+ TP_locvar(
+ unsigned int fds_length, fds_max_len;
+ struct pollfd *fds;
+ unsigned int alloc_fds;
+ unsigned int overflow;
+ ),
+ TP_code_pre(
+ BUILD_BUG_ON(((ARRAY_SIZE(lttng_pollfd_flag_fields) - 1) +
+ POLL_FLAGS_PADDING_SIZE) !=
+ sizeof(uint8_t) * BITS_PER_BYTE);
+ tp_locvar->fds = NULL;
+ tp_locvar->overflow = 0;
+
+ sc_in(
+ if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
+ tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->fds_length = nfds;
+ tp_locvar->fds_max_len = nfds;
+ }
+ tp_locvar->alloc_fds = tp_locvar->fds_length * sizeof(struct pollfd);
+ )
+ /*
+ * On exit, the number of active FDs is determined by ret,
+ * nfds stays the same as the entry, but we only want to
+ * output the FDs that are relevant.
+ */
+ sc_out(
+ if (ret <= 0 || ret > nfds)
+ goto error;
+
+ if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
+ tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->fds_length = ret;
+ tp_locvar->fds_max_len = nfds;
+ }
+ tp_locvar->alloc_fds = tp_locvar->fds_max_len * sizeof(struct pollfd);
+ )
+ {
+ int err;
+
+ tp_locvar->fds = kmalloc(tp_locvar->alloc_fds, GFP_ATOMIC);
+ if (!tp_locvar->fds)
+ goto error;
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds, ufds,
+ nfds * sizeof(struct pollfd));
+ if (err != 0)
+ goto error;
+ }
+ goto end;
+
+ error:
+ tp_locvar->fds_length = 0;
+ tp_locvar->fds_max_len = 0;
+ end:
+ ;
+ ),
+ TP_FIELDS(
+ sc_exit(ctf_integer(long, ret, ret))
+ sc_in(ctf_integer(int, timeout_msecs, timeout_msecs))
+ sc_inout(ctf_integer(unsigned int, nfds, nfds))
+ sc_inout(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
+ sc_in(ctf_integer(int, overflow, tp_locvar->overflow))
+ sc_in(
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence_compound,
+ .u.sequence_compound.length_name = "fds_length",
+ .u.sequence_compound.elem_type = <tng_pollfd_elem,
+ ),
+ fds,
+ ctf_custom_code(
+ uint32_t i;
+
+ ctf_align(int) /* Align on largest field in struct. */
+ for (i = 0; i < tp_locvar->fds_length; i++) {
+ ctf_integer_type(int, tp_locvar->fds[i].fd)
+ ctf_integer_type(short, tp_locvar->fds[i].events)
+ ctf_integer_bitfield_type(uint8_t,
+ (uint8_t) tp_locvar->fds[i].events)
+ }
+ )
+ )
+ )
+ sc_out(
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence_compound,
+ .u.sequence_compound.length_name = "fds_length",
+ .u.sequence_compound.elem_type = <tng_pollfd_elem,
+ ),
+ fds,
+ ctf_custom_code(
+ uint32_t i;
+ unsigned int nr = 0;
+
+ ctf_align(int) /* Align on largest field in struct. */
+ /*
+ * Iterate over the complete array, but only output
+ * "ret" active FDs.
+ */
+ for (i = 0; i < tp_locvar->fds_max_len; i++) {
+ if (!tp_locvar->fds[i].revents)
+ continue;
+ if (++nr > tp_locvar->fds_length)
+ break;
+ ctf_integer_type(int, tp_locvar->fds[i].fd)
+ ctf_integer_type(short, tp_locvar->fds[i].revents)
+ ctf_integer_bitfield_type(uint8_t,
+ (uint8_t) tp_locvar->fds[i].revents)
+ }
+ /*
+ * If there is a discrepancy between ret and the
+ * content of revents (e.g. caused by userspace corrupting
+ * the array from a concurrent thread), we have to output
+ * zeros to keep the trace readable.
+ */
+ for (i = nr; i < tp_locvar->fds_length - nr; i++) {
+ ctf_integer_type(int, 0)
+ ctf_integer_type(short, 0)
+ ctf_integer_bitfield_type(uint8_t, 0)
+ }
+ )
+ )
+ )
+ ),
+ TP_code_post(
+ kfree(tp_locvar->fds);
+ )
+)
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM)
+#define OVERRIDE_32_ppoll
+#define OVERRIDE_64_ppoll
+SC_LTTNG_TRACEPOINT_EVENT_CODE(ppoll,
+ TP_PROTO(sc_exit(long ret,) struct pollfd __user * ufds,
+ unsigned int nfds, struct timespec * tsp, const sigset_t * sigmask, size_t sigsetsize),
+ TP_ARGS(sc_exit(ret,) ufds, nfds, tsp, sigmask, sigsetsize),
+ TP_locvar(
+ unsigned int fds_length, fds_max_len;
+ struct pollfd *fds;
+ unsigned int alloc_fds;
+ unsigned int overflow;
+ ),
+ TP_code_pre(
+ BUILD_BUG_ON(((ARRAY_SIZE(lttng_pollfd_flag_fields) - 1) +
+ POLL_FLAGS_PADDING_SIZE) !=
+ sizeof(uint8_t) * BITS_PER_BYTE);
+ tp_locvar->fds = NULL;
+ tp_locvar->overflow = 0;
+
+ sc_in(
+ if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
+ tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->fds_length = nfds;
+ tp_locvar->fds_max_len = nfds;
+ }
+ tp_locvar->alloc_fds = tp_locvar->fds_length * sizeof(struct pollfd);
+ )
+ /*
+ * On exit, the number of active FDs is determined by ret,
+ * nfds stays the same as the entry, but we only want to
+ * output the FDs that are relevant.
+ */
+ sc_out(
+ if (ret <= 0 || ret > nfds)
+ goto error;
+
+ if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
+ tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->fds_length = ret;
+ tp_locvar->fds_max_len = nfds;
+ }
+ tp_locvar->alloc_fds = tp_locvar->fds_max_len * sizeof(struct pollfd);
+ )
+ {
+ int err;
+
+ tp_locvar->fds = kmalloc(tp_locvar->alloc_fds, GFP_ATOMIC);
+ if (!tp_locvar->fds)
+ goto error;
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->fds, ufds,
+ nfds * sizeof(struct pollfd));
+ if (err != 0)
+ goto error;
+ }
+ goto end;
+
+ error:
+ tp_locvar->fds_length = 0;
+ tp_locvar->fds_max_len = 0;
+ end:
+ ;
+ ),
+ TP_FIELDS(
+ sc_exit(ctf_integer(long, ret, ret))
+ sc_in(ctf_integer(struct timespec *, tsp, tsp))
+ sc_in(ctf_integer(const sigset_t *, sigmask, sigmask))
+ sc_in(ctf_integer(size_t, sigsetsize, sigsetsize))
+ sc_inout(ctf_integer(unsigned int, nfds, nfds))
+ sc_inout(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
+ sc_inout(ctf_integer(int, overflow, tp_locvar->overflow))
+ sc_in(
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence_compound,
+ .u.sequence_compound.length_name = "fds_length",
+ .u.sequence_compound.elem_type = <tng_pollfd_elem,
+ ),
+ fds,
+ ctf_custom_code(
+ uint32_t i;
+
+ ctf_align(int) /* Align on largest field in struct. */
+ for (i = 0; i < tp_locvar->fds_length; i++) {
+ ctf_integer_type(int, tp_locvar->fds[i].fd)
+ ctf_integer_type(short, tp_locvar->fds[i].events)
+ ctf_integer_bitfield_type(uint8_t,
+ (uint8_t) tp_locvar->fds[i].events)
+ }
+ )
+ )
+ )
+ sc_out(
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence_compound,
+ .u.sequence_compound.length_name = "fds_length",
+ .u.sequence_compound.elem_type = <tng_pollfd_elem,
+ ),
+ fds,
+ ctf_custom_code(
+ uint32_t i;
+ unsigned int nr = 0;
+
+ ctf_align(int) /* Align on largest field in struct. */
+ /*
+ * Iterate over the complete array, but only output
+ * "ret" active FDs.
+ */
+ for (i = 0; i < tp_locvar->fds_max_len; i++) {
+ if (!tp_locvar->fds[i].revents)
+ continue;
+ if (++nr > tp_locvar->fds_length)
+ break;
+ ctf_integer_type(int, tp_locvar->fds[i].fd)
+ ctf_integer_type(short, tp_locvar->fds[i].revents)
+ ctf_integer_bitfield_type(uint8_t,
+ (uint8_t) tp_locvar->fds[i].revents)
+ }
+ /*
+ * If there is a discrepancy between ret and the
+ * content of revents (e.g. caused by userspace corrupting
+ * the array from a concurrent thread), we have to output
+ * zeros to keep the trace readable.
+ */
+ for (i = nr; i < tp_locvar->fds_length - nr; i++) {
+ ctf_integer_type(int, 0)
+ ctf_integer_type(short, 0)
+ ctf_integer_bitfield_type(uint8_t, 0)
+ }
+ )
+ )
+ )
+ ),
+ TP_code_post(
+ kfree(tp_locvar->fds);
+ )
+)
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
+
#endif /* CREATE_SYSCALL_TABLE */
--
1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 4/5] Extract the payload for epoll_ctl
2016-04-23 0:16 [lttng-dev] [PATCH lttng-modules v5 0/5] Extract payload from polling syscalls Julien Desfossez
` (2 preceding siblings ...)
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 3/5] Extract the FDs and flags from poll and ppoll Julien Desfossez
@ 2016-04-23 0:16 ` Julien Desfossez
2016-04-29 18:35 ` Mathieu Desnoyers
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 5/5] Extract the payload of epoll_wait/epoll_pwait Julien Desfossez
4 siblings, 1 reply; 12+ messages in thread
From: Julien Desfossez @ 2016-04-23 0:16 UTC (permalink / raw)
Map the operation to its name (EPOLL_CTL_*), extract the standard event
flags (EPOLL*) and output the data in two different formats: FD as an
int in decimal, and u64 in hex. The less standard event flags are not
extracted yet, but we extract the raw value in hex for more advanced
analyses.
Here is an example output:
syscall_entry_epoll_ctl: {
epfd = 4, op_enum = ( "EPOLL_CTL_ADD" : container = 1 ),
fd = 0, event = { raw_events = 0x80000003,
events = { EPOLLIN = 1, EPOLLPRI = 1, EPOLLOUT = 0, EPOLLERR = 0,
padding = 0 },
data_union = { u64 = 0x0, fd = 0 } }
}
syscall_exit_epoll_ctl: { ret = 0 }
Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
---
| 139 +++++++++++++++++++++
1 file changed, 139 insertions(+)
--git a/instrumentation/syscalls/headers/syscalls_pointers_override.h b/instrumentation/syscalls/headers/syscalls_pointers_override.h
index 6ade85c..9fe0030 100644
--- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
+++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
@@ -923,4 +923,143 @@ SC_LTTNG_TRACEPOINT_EVENT_CODE(ppoll,
)
#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
+#include <linux/eventpoll.h>
+
+SC_LTTNG_TRACEPOINT_ENUM(lttng_epoll_op,
+ TP_ENUM_VALUES(
+ ctf_enum_value("EPOLL_CTL_ADD", EPOLL_CTL_ADD)
+ ctf_enum_value("EPOLL_CTL_DEL", EPOLL_CTL_DEL)
+ ctf_enum_value("EPOLL_CTL_MOD", EPOLL_CTL_MOD)
+ )
+)
+
+#ifndef ONCE_LTTNG_TRACE_EPOLL_CTL_H
+#define ONCE_LTTNG_TRACE_EPOLL_CTL_H
+
+#define LTTNG_EPOLL_NRFLAGS (POLLHUP + 1)
+#define EPOLL_FLAGS_PADDING_SIZE (sizeof(uint8_t) * BITS_PER_BYTE) - ilog2(LTTNG_EPOLL_NRFLAGS - 1)
+
+/*
+ * Only extract the values specified by iBCS2 for now.
+ */
+static struct lttng_event_field lttng_epoll_ctl_events_fields[] = {
+ /* 0x0001 */
+ [ilog2(POLLIN)] = {
+ .name = "EPOLLIN",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ /* 0x0002 */
+ [ilog2(POLLPRI)] = {
+ .name = "EPOLLPRI",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ /* 0x0004 */
+ [ilog2(POLLOUT)] = {
+ .name = "EPOLLOUT",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ /* 0x0008 */
+ [ilog2(POLLERR)] = {
+ .name = "EPOLLERR",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ /* 0x0010 */
+ [ilog2(POLLHUP)] = {
+ .name = "EPOLLHUP",
+ .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
+ },
+ [ilog2(LTTNG_EPOLL_NRFLAGS)] = {
+ .name = "padding",
+ .type = __type_integer(int, EPOLL_FLAGS_PADDING_SIZE, 1, 0,
+ __LITTLE_ENDIAN, 10, none),
+ },
+
+};
+
+static struct lttng_event_field lttng_epoll_data_fields[] = {
+ [0] = {
+ .name = "u64",
+ .type = __type_integer(uint64_t, 0, 0, 0, __BYTE_ORDER, 16, none),
+ },
+ [1] = {
+ .name = "fd",
+ .type = __type_integer(int, 0, 0, 0, __BYTE_ORDER, 10, none),
+ },
+};
+
+static struct lttng_event_field epoll_ctl_fields[] = {
+ [0] = {
+ .name = "data_union",
+ .type = {
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_data_fields),
+ .u._struct.fields = lttng_epoll_data_fields,
+ }
+ },
+ [1] = {
+ .name = "raw_events",
+ .type = __type_integer(uint32_t, 0, 0, 0, __BYTE_ORDER, 16, none),
+ },
+ [2] = {
+ .name = "events",
+ .type = {
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_ctl_events_fields),
+ .u._struct.fields = lttng_epoll_ctl_events_fields,
+ }
+ },
+};
+#endif /* ONCE_LTTNG_TRACE_EPOLL_CTL_H */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM)
+#define OVERRIDE_32_epoll_ctl
+#define OVERRIDE_64_epoll_ctl
+SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_ctl,
+ TP_PROTO(sc_exit(long ret,) int epfd, int op, int fd,
+ struct epoll_event __user * uevent),
+ TP_ARGS(sc_exit(ret,) epfd, op, fd, uevent),
+ TP_locvar(
+ struct epoll_event event;
+ int err;
+ ),
+ TP_code_pre(
+ tp_locvar->err = lib_ring_buffer_copy_from_user_check_nofault(
+ &tp_locvar->event, uevent, sizeof(struct epoll_event));
+ ),
+ TP_FIELDS(
+ sc_exit(ctf_integer(long, ret, ret))
+ sc_in(ctf_integer(int, epfd, epfd))
+ sc_in(ctf_enum(lttng_epoll_op, int, op_enum, op))
+ sc_in(ctf_integer(int, fd, fd))
+ sc_in(
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(epoll_ctl_fields),
+ .u._struct.fields = epoll_ctl_fields,
+ ),
+ event,
+ ctf_custom_code(
+ ctf_align(uint64_t)
+ if (!tp_locvar->err) {
+ ctf_integer_type(uint64_t, tp_locvar->event.data)
+ ctf_integer_type(int, tp_locvar->event.data)
+ ctf_integer_bitfield_type(uint32_t,
+ cpu_to_le32(tp_locvar->event.events))
+ ctf_integer_bitfield_type(uint8_t,
+ (uint8_t) cpu_to_le32(tp_locvar->event.events))
+ } else {
+ ctf_integer_type(uint64_t, 0)
+ ctf_integer_type(int, 0)
+ ctf_integer_bitfield_type(uint32_t, 0)
+ ctf_integer_bitfield_type(uint8_t, 0)
+ }
+ )
+ )
+ )
+ ),
+ TP_code_post()
+)
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
+
#endif /* CREATE_SYSCALL_TABLE */
--
1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 5/5] Extract the payload of epoll_wait/epoll_pwait
2016-04-23 0:16 [lttng-dev] [PATCH lttng-modules v5 0/5] Extract payload from polling syscalls Julien Desfossez
` (3 preceding siblings ...)
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 4/5] Extract the payload for epoll_ctl Julien Desfossez
@ 2016-04-23 0:16 ` Julien Desfossez
2016-04-29 18:45 ` Mathieu Desnoyers
4 siblings, 1 reply; 12+ messages in thread
From: Julien Desfossez @ 2016-04-23 0:16 UTC (permalink / raw)
When epoll_wait returns, extract the content of the "events" field
(events set and data payload).
Here is an example output:
syscall_entry_epoll_wait: { epfd = 3, maxevents = 32, timeout = 100 }
syscall_exit_epoll_wait: { ret = 1, fds_length = 1,
fds = [ [0] = { raw_events = 0x1,
events = { EPOLLIN = 1, EPOLLPRI = 0, EPOLLOUT = 0, EPOLLERR = 0,
padding = 0 },
data_union = { u64 = 0x100000005, fd = 5 } } ]
}
Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
---
| 234 +++++++++++++++++++++
1 file changed, 234 insertions(+)
--git a/instrumentation/syscalls/headers/syscalls_pointers_override.h b/instrumentation/syscalls/headers/syscalls_pointers_override.h
index 9fe0030..68ba1a2 100644
--- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
+++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
@@ -1062,4 +1062,238 @@ SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_ctl,
)
#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
+#ifndef ONCE_LTTNG_TRACE_EPOLL_H
+#define ONCE_LTTNG_TRACE_EPOLL_H
+
+static struct lttng_event_field lttng_epoll_wait_fields[] = {
+ [0] = {
+ .name = "data_union",
+ .type = {
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_data_fields),
+ .u._struct.fields = lttng_epoll_data_fields,
+ }
+ },
+ [1] = {
+ .name = "raw_events",
+ .type = __type_integer(uint32_t, 0, 0, 0, __BYTE_ORDER, 16, none),
+ },
+ [2] = {
+ .name = "events",
+ .type = {
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_ctl_events_fields),
+ .u._struct.fields = lttng_epoll_ctl_events_fields,
+ }
+ },
+};
+
+static struct lttng_type lttng_epoll_wait_elem = {
+ .atype = atype_struct,
+ .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_wait_fields),
+ .u._struct.fields = lttng_epoll_wait_fields,
+};
+
+#endif /* ONCE_LTTNG_TRACE_EPOLL_H */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64)
+#define OVERRIDE_32_epoll_wait
+#define OVERRIDE_64_epoll_wait
+SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_wait,
+ TP_PROTO(sc_exit(long ret,) int epfd, struct epoll_event __user * uevents,
+ int maxevents, int timeout),
+ TP_ARGS(sc_exit(ret,) epfd, uevents, maxevents, timeout),
+ TP_locvar(
+ sc_out(
+ unsigned int fds_length, overflow;
+ struct epoll_event *events;
+ )
+ ),
+ TP_code_pre(
+ BUILD_BUG_ON(((ARRAY_SIZE(lttng_epoll_ctl_events_fields) - 1) +
+ EPOLL_FLAGS_PADDING_SIZE) !=
+ sizeof(uint8_t) * BITS_PER_BYTE);
+ sc_out({
+ int err;
+ unsigned long maxalloc;
+
+ tp_locvar->fds_length = 0;
+ tp_locvar->events = NULL;
+ tp_locvar->overflow = 0;
+
+ if (maxevents <= 0 || ret <= 0 || ret > maxevents)
+ goto skip_code;
+
+ if ((maxevents * sizeof(struct epoll_event)) > PAGE_SIZE) {
+ maxalloc = PAGE_SIZE / sizeof(struct epoll_event);
+ if (ret > maxalloc) {
+ tp_locvar->fds_length = maxalloc;
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->fds_length = ret;
+ }
+ } else {
+ maxalloc = maxevents;
+ tp_locvar->fds_length = ret;
+ }
+
+ tp_locvar->events = kmalloc(
+ maxalloc * sizeof(struct epoll_event),
+ GFP_ATOMIC);
+ if (!tp_locvar->events) {
+ tp_locvar->fds_length = 0;
+ goto skip_code;
+ }
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->events, uevents,
+ maxevents * sizeof(struct epoll_event));
+ if (err != 0)
+ tp_locvar->fds_length = 0;
+ }
+ skip_code:
+ )
+ ),
+ TP_FIELDS(
+ sc_exit(ctf_integer(long, ret, ret))
+ sc_in(ctf_integer(int, epfd, epfd))
+ sc_in(ctf_integer(int, maxevents, maxevents))
+ sc_in(ctf_integer(int, timeout, timeout))
+ sc_out(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
+ sc_out(ctf_integer(int, overflow, tp_locvar->overflow))
+ sc_out(
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence_compound,
+ .u.sequence_compound.length_name =
+ "fds_length",
+ .u.sequence_compound.elem_type =
+ <tng_epoll_wait_elem,
+ ),
+ fds,
+ ctf_custom_code(
+ uint32_t i;
+
+ ctf_align(uint64_t)
+ for (i = 0; i < tp_locvar->fds_length; i++) {
+ ctf_integer_type(uint64_t, tp_locvar->events[i].data)
+ ctf_integer_type(int, tp_locvar->events[i].data)
+ ctf_integer_bitfield_type(uint32_t,
+ cpu_to_le32(tp_locvar->events[i].events))
+ ctf_integer_bitfield_type(uint8_t,
+ (uint8_t) cpu_to_le32(tp_locvar->events[i].events))
+ }
+ )
+ )
+ )
+ ),
+ TP_code_post(
+ sc_out(
+ kfree(tp_locvar->events);
+ )
+ )
+)
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM)
+#define OVERRIDE_32_epoll_pwait
+#define OVERRIDE_64_epoll_pwait
+SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_pwait,
+ TP_PROTO(sc_exit(long ret,) int epfd, struct epoll_event __user * uevents,
+ int maxevents, int timeout, const sigset_t * sigmask, size_t sigsetsize),
+ TP_ARGS(sc_exit(ret,) epfd, uevents, maxevents, timeout, sigmask, sigsetsize),
+ TP_locvar(
+ sc_out(
+ unsigned int fds_length, overflow;
+ struct epoll_event *events;
+ )
+ ),
+ TP_code_pre(
+ BUILD_BUG_ON(((ARRAY_SIZE(lttng_epoll_ctl_events_fields) - 1) +
+ EPOLL_FLAGS_PADDING_SIZE) !=
+ sizeof(uint8_t) * BITS_PER_BYTE);
+ sc_out({
+ int err;
+ unsigned long maxalloc;
+
+ tp_locvar->fds_length = 0;
+ tp_locvar->events = NULL;
+ tp_locvar->overflow = 0;
+
+ if (maxevents <= 0 || ret <= 0 || ret > maxevents)
+ goto skip_code;
+
+ if ((maxevents * sizeof(struct epoll_event)) > PAGE_SIZE) {
+ maxalloc = PAGE_SIZE / sizeof(struct epoll_event);
+ if (ret > maxalloc) {
+ tp_locvar->fds_length = maxalloc;
+ tp_locvar->overflow = 1;
+ } else {
+ tp_locvar->fds_length = ret;
+ }
+ } else {
+ maxalloc = maxevents;
+ tp_locvar->fds_length = ret;
+ }
+
+ tp_locvar->events = kmalloc(
+ maxalloc * sizeof(struct epoll_event),
+ GFP_ATOMIC);
+ if (!tp_locvar->events) {
+ tp_locvar->fds_length = 0;
+ goto skip_code;
+ }
+
+ err = lib_ring_buffer_copy_from_user_check_nofault(
+ tp_locvar->events, uevents,
+ maxevents * sizeof(struct epoll_event));
+ if (err != 0)
+ tp_locvar->fds_length = 0;
+ }
+ skip_code:
+ )
+ ),
+ TP_FIELDS(
+ sc_exit(ctf_integer(long, ret, ret))
+ sc_in(ctf_integer(int, epfd, epfd))
+ sc_in(ctf_integer(int, maxevents, maxevents))
+ sc_in(ctf_integer(int, timeout, timeout))
+ sc_in(ctf_integer(const sigset_t *, sigmask, sigmask))
+ sc_in(ctf_integer(size_t, sigsetsize, sigsetsize))
+ sc_out(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
+ sc_out(ctf_integer(int, overflow, tp_locvar->overflow))
+ sc_out(
+ ctf_custom_field(
+ ctf_custom_type(
+ .atype = atype_sequence_compound,
+ .u.sequence_compound.length_name =
+ "fds_length",
+ .u.sequence_compound.elem_type =
+ <tng_epoll_wait_elem,
+ ),
+ fds,
+ ctf_custom_code(
+ uint32_t i;
+
+ ctf_align(uint64_t)
+ for (i = 0; i < tp_locvar->fds_length; i++) {
+ ctf_integer_type(uint64_t, tp_locvar->events[i].data)
+ ctf_integer_type(int, tp_locvar->events[i].data)
+ ctf_integer_bitfield_type(uint32_t,
+ cpu_to_le32(tp_locvar->events[i].events))
+ ctf_integer_bitfield_type(uint8_t,
+ (uint8_t) cpu_to_le32(tp_locvar->events[i].events))
+ }
+ )
+ )
+ )
+ ),
+ TP_code_post(
+ sc_out(
+ kfree(tp_locvar->events);
+ )
+ )
+)
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
+
#endif /* CREATE_SYSCALL_TABLE */
--
1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6 Julien Desfossez
@ 2016-04-25 20:42 ` Julien Desfossez
2016-04-29 18:13 ` Mathieu Desnoyers
1 sibling, 0 replies; 12+ messages in thread
From: Julien Desfossez @ 2016-04-25 20:42 UTC (permalink / raw)
> + if (inp) {
> + tp_locvar->fds_in = kmalloc(
> + tp_locvar->nr_ulong * sizeof(unsigned long),
> + GFP_ATOMIC);
I replaced "GFP_ATOMIC" by "GFP_ATOMIC | GFP_NOWAIT" for every
allocation in this patch serie because ATOMIC does not imply NOWAIT.
Julien
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6 Julien Desfossez
2016-04-25 20:42 ` Julien Desfossez
@ 2016-04-29 18:13 ` Mathieu Desnoyers
2016-04-29 18:25 ` Mathieu Desnoyers
1 sibling, 1 reply; 12+ messages in thread
From: Mathieu Desnoyers @ 2016-04-29 18:13 UTC (permalink / raw)
----- On Apr 22, 2016, at 8:16 PM, Julien Desfossez jdesfossez at efficios.com wrote:
> Instead of extracting the user-space pointers of the 3 fd_set, we now
> extract the bitmask of the FDs in the sets (in, out, ex) in the form of
> an array of uint8_t (1024 FDs is the limit in the kernel).
>
> In this example, we select in input FDs 5 to 19 (0xFFFF0), it returns
> that one FD is ready: FD 12 (0x1000).
>
> syscall_entry_select: {
> n = 20,
> _fdset_in_length = 3, fdset_in = [ [0] = 0xF0, [1] = 0xFF, [2] = 0xF ],
> _fdset_out_length = 0, fdset_out = [ ],
> _fdset_ex_length = 0, fdset_ex = [ ],
> tvp = 0
> }
>
> syscall_exit_select: {
> ret = 1,
> _fdset_in_length = 3, fdset_in = [ [0] = 0x0, [1] = 0x10, [2] = 0x0 ],
> _fdset_out_length = 0, fdset_out = [ ],
> _fdset_ex_length = 0, fdset_ex = [ ],
> tvp = 0
> }
>
> Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
> ---
> .../syscalls/headers/syscalls_pointers_override.h | 510 +++++++++++++++++++++
> 1 file changed, 510 insertions(+)
>
> diff --git a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> index bf5c632..ef4dc1c 100644
> --- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> +++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> @@ -53,4 +53,514 @@ SC_LTTNG_TRACEPOINT_EVENT(pipe2,
> )
> )
>
> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64)
> +#define OVERRIDE_32_select
> +#define OVERRIDE_64_select
> +SC_LTTNG_TRACEPOINT_EVENT_CODE(select,
> + TP_PROTO(sc_exit(long ret,) int n, fd_set __user *inp, fd_set __user *outp,
> + fd_set __user *exp, struct timeval *tvp),
> + TP_ARGS(sc_exit(ret,) n, inp, outp, exp, tvp),
> + TP_locvar(
> + unsigned long *fds_in, *fds_out, *fds_ex;
> + unsigned long nr_bytes, nr_ulong;
> + unsigned int overflow;
Change for uint8_t for overflow.
> + ),
> + TP_code_pre(
> + sc_inout(
> + {
> + int err;
> +
> + tp_locvar->fds_in = NULL;
> + tp_locvar->fds_out = NULL;
> + tp_locvar->fds_ex = NULL;
> +
remove newline.
> + tp_locvar->overflow = 0;
> +
> + sc_out(
> + if (ret <= 0)
> + goto error;
> + )
> +
> + if (n <= 0)
> + goto error;
> +
> + /* Limit atomic memory allocation to one page */
> + if (DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) > PAGE_SIZE) {
Put DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) into local variable.
> + tp_locvar->nr_bytes = PAGE_SIZE;
> + tp_locvar->nr_ulong = PAGE_SIZE / sizeof(unsigned long);
> + /* Inform the user that we did not output everything. */
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->nr_bytes = DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE);
> + tp_locvar->nr_ulong = DIV_ROUND_UP((unsigned int) n,
> + BITS_PER_BYTE * sizeof(unsigned long));
> + }
> + /* On error or bogus input, don't copy anything. */
> + if (tp_locvar->nr_bytes > (__FD_SETSIZE / (8 * sizeof(uint8_t)))) {
Replace 8 by BITS_PER_BYTE
Move this check before the comparison with PAGE_SIZE.
A "n" larger than 1023 is an error....
Test on "n" rather than nr_bytes.
nr_bytes will therefore never be over on page on linux.
We could put a WARN_ON_ONCE() and goto error for it instead of the ceiling.
> + goto error;
> + }
> +
> + if (inp) {
> + tp_locvar->fds_in = kmalloc(
> + tp_locvar->nr_ulong * sizeof(unsigned long),
> + GFP_ATOMIC);
| GFP_NOWAIT as discussed.
> + if (!tp_locvar->fds_in)
> + goto error;
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds_in, inp,
> + tp_locvar->nr_ulong * sizeof(unsigned long));
> + if (err != 0)
> + goto error;
> + }
> + if (outp) {
> + tp_locvar->fds_out = kmalloc(
> + tp_locvar->nr_ulong * sizeof(unsigned long),
> + GFP_ATOMIC);
.....
> + if (!tp_locvar->fds_out)
> + goto error;
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds_out, outp,
> + tp_locvar->nr_ulong * sizeof(unsigned long));
> + if (err != 0)
> + goto error;
> + }
> + if (exp) {
> + tp_locvar->fds_ex = kmalloc(
> + tp_locvar->nr_ulong * sizeof(unsigned long),
> + GFP_ATOMIC);
.........
> + if (!tp_locvar->fds_ex)
> + goto error;
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds_ex, exp,
> + tp_locvar->nr_ulong * sizeof(unsigned long));
> + if (err != 0)
> + goto error;
> + }
> + goto end;
> +
> + error:
> + tp_locvar->nr_bytes = 0;
> + tp_locvar->nr_ulong = 0;
> + end:
> + /* bypass error: label at end of compound statement */
Reword to /* Label at end of compound statement. */
> + ;
Mod line to:
end: ; /* Label at end of compound statement. */
> + }
> + )
> + ),
> + TP_FIELDS(
> + sc_exit(ctf_integer(long, ret, ret))
> + sc_in(ctf_integer(int, n, n))
> + sc_inout(ctf_integer(int, overflow, tp_locvar->overflow))
uint8_t
> + sc_inout(ctf_integer(struct timeval *, tvp, tvp))
> +
> + sc_inout(
> + /* inp */
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence,
> + .u.sequence.length_type = __type_integer(
> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
uint8_t is enough. (1024/8=128)
> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
> + __BYTE_ORDER, 16, none),
> + ),
> + readfds,
> + ctf_custom_code(
> + unsigned int src;
> + unsigned int nr_bytes_out = 0;
> +
> + if (inp) {
> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
uint8_t
> + ctf_align(uint8_t)
> + } else {
> + ctf_integer_type(uint16_t, 0)
uint8_t
> + ctf_align(uint8_t)
> + goto skip_inp;
> + }
> +
> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
> + int dst;
> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
> + for (dst = 0; dst < sizeof(long); dst++) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_inp;
> + }
> + }
> +#else
> + for (dst = sizeof(long); dst >= 0; dst--) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_inp;
> + }
> + }
> +#endif
> + }
> + skip_inp:
> + ;
> + )
3 macros (nested) rather than cut n paste.
> + )
> + /* outp */
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence,
> + .u.sequence.length_type = __type_integer(
> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
> + __BYTE_ORDER, 16, none),
> + ),
> + writefds,
> + ctf_custom_code(
> + unsigned int src;
> + unsigned int nr_bytes_out = 0;
> +
> + if (outp) {
> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
> + ctf_align(uint8_t)
> + } else {
> + ctf_integer_type(uint16_t, 0)
> + ctf_align(uint8_t)
> + goto skip_outp;
> + }
> +
> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
> + int dst;
> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
> + for (dst = 0; dst < sizeof(long); dst++) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_outp;
> + }
> + }
> +#else
> + for (dst = sizeof(long); dst >= 0; dst--) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_outp;
> + }
> + }
> +#endif
> + }
> + skip_outp:
> + ;
> + )
> + )
> + /* exp */
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence,
> + .u.sequence.length_type = __type_integer(
> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
> + __BYTE_ORDER, 16, none),
> + ),
> + exceptfds,
> + ctf_custom_code(
> + unsigned int src;
> + unsigned int nr_bytes_out = 0;
> +
> + if (exp) {
> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
> + ctf_align(uint8_t)
> + } else {
> + ctf_integer_type(uint16_t, 0)
> + ctf_align(uint8_t)
> + goto skip_exp;
> + }
> +
> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
> + int dst;
> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
> + for (dst = 0; dst < sizeof(long); dst++) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_exp;
> + }
> + }
> +#else
> + for (dst = sizeof(long); dst >= 0; dst--) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_exp;
> + }
> + }
> +#endif
> + }
> + skip_exp:
> + ;
> + )
> + )
> + )
> + ),
> + TP_code_post(
> + kfree(tp_locvar->fds_in);
> + kfree(tp_locvar->fds_out);
> + kfree(tp_locvar->fds_ex);
> + )
> +)
> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) */
> +
> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64)
> || defined(CONFIG_ARM)
> +#define OVERRIDE_32_pselect6
> +#define OVERRIDE_64_pselect6
> +SC_LTTNG_TRACEPOINT_EVENT_CODE(pselect6,
> + TP_PROTO(sc_exit(long ret,) int n, fd_set __user * inp, fd_set __user * outp,
> + fd_set __user * exp, struct timeval * tvp, void * sig),
> + TP_ARGS(sc_exit(ret,) n, inp, outp, exp, tvp, sig),
> + TP_locvar(
Please combine into a macro with select.
> + unsigned long *fds_in, *fds_out, *fds_ex;
> + unsigned long nr_bytes, nr_ulong;
> + unsigned int overflow;
> + ),
> + TP_code_pre(
> + sc_inout(
> + {
> + int err;
> +
> + tp_locvar->fds_in = NULL;
> + tp_locvar->fds_out = NULL;
> + tp_locvar->fds_ex = NULL;
> +
> + tp_locvar->overflow = 0;
> +
> + sc_out(
> + if (ret <= 0)
> + goto error;
> + )
> +
> + if (n <= 0)
> + goto error;
> +
> + /* Limit atomic memory allocation to one page */
> + if (DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) > PAGE_SIZE) {
> + tp_locvar->nr_bytes = PAGE_SIZE;
> + tp_locvar->nr_ulong = PAGE_SIZE / sizeof(unsigned long);
> + /* Inform the user that we did not output everything. */
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->nr_bytes = DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE);
> + tp_locvar->nr_ulong = DIV_ROUND_UP((unsigned int) n,
> + BITS_PER_BYTE * sizeof(unsigned long));
> + }
> + /* On error or bogus input, don't copy anything. */
> + if (tp_locvar->nr_bytes > (__FD_SETSIZE / (8 * sizeof(uint8_t)))) {
> + goto error;
> + }
> +
> + if (inp) {
> + tp_locvar->fds_in = kmalloc(
> + tp_locvar->nr_ulong * sizeof(unsigned long),
> + GFP_ATOMIC);
> + if (!tp_locvar->fds_in)
> + goto error;
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds_in, inp,
> + tp_locvar->nr_ulong * sizeof(unsigned long));
> + if (err != 0)
> + goto error;
> + }
> + if (outp) {
> + tp_locvar->fds_out = kmalloc(
> + tp_locvar->nr_ulong * sizeof(unsigned long),
> + GFP_ATOMIC);
> + if (!tp_locvar->fds_out)
> + goto error;
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds_out, outp,
> + tp_locvar->nr_ulong * sizeof(unsigned long));
> + if (err != 0)
> + goto error;
> + }
> + if (exp) {
> + tp_locvar->fds_ex = kmalloc(
> + tp_locvar->nr_ulong * sizeof(unsigned long),
> + GFP_ATOMIC);
> + if (!tp_locvar->fds_ex)
> + goto error;
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds_ex, exp,
> + tp_locvar->nr_ulong * sizeof(unsigned long));
> + if (err != 0)
> + goto error;
> + }
> + goto end;
> +
> + error:
> + tp_locvar->nr_bytes = 0;
> + tp_locvar->nr_ulong = 0;
> + end:
> + /* bypass error: label at end of compound statement */
> + ;
> + }
> + )
> + ),
> + TP_FIELDS(
> + sc_exit(ctf_integer(long, ret, ret))
> + sc_in(ctf_integer(int, n, n))
> + sc_in(ctf_integer(int, overflow, tp_locvar->overflow))
> + sc_inout(ctf_integer(struct timeval *, tvp, tvp))
> +
> + sc_inout(
> + /* inp */
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence,
> + .u.sequence.length_type = __type_integer(
> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
> + __BYTE_ORDER, 16, none),
> + ),
> + readfds,
> + ctf_custom_code(
> + unsigned int src;
> + unsigned int nr_bytes_out = 0;
> +
> + if (inp) {
> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
> + ctf_align(uint8_t)
> + } else {
> + ctf_integer_type(uint16_t, 0)
> + ctf_align(uint8_t)
> + goto skip_inp;
> + }
> +
> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
> + int dst;
> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
> + for (dst = 0; dst < sizeof(long); dst++) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_inp;
> + }
> + }
> +#else
> + for (dst = sizeof(long); dst >= 0; dst--) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_inp;
> + }
> + }
> +#endif
> + }
> + skip_inp:
> + ;
> + )
> + )
> + /* outp */
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence,
> + .u.sequence.length_type = __type_integer(
> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
> + __BYTE_ORDER, 16, none),
> + ),
> + writefds,
> + ctf_custom_code(
> + unsigned int src;
> + unsigned int nr_bytes_out = 0;
> +
> + if (outp) {
> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
> + ctf_align(uint8_t)
> + } else {
> + ctf_integer_type(uint16_t, 0)
> + ctf_align(uint8_t)
> + goto skip_outp;
> + }
> +
> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
> + int dst;
> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
> + for (dst = 0; dst < sizeof(long); dst++) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_outp;
> + }
> + }
> +#else
> + for (dst = sizeof(long); dst >= 0; dst--) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_outp;
> + }
> + }
> +#endif
> + }
> + skip_outp:
> + ;
> + )
> + )
> + /* exp */
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence,
> + .u.sequence.length_type = __type_integer(
> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
> + __BYTE_ORDER, 16, none),
> + ),
> + exceptfds,
> + ctf_custom_code(
> + unsigned int src;
> + unsigned int nr_bytes_out = 0;
> +
> + if (exp) {
> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
> + ctf_align(uint8_t)
> + } else {
> + ctf_integer_type(uint16_t, 0)
> + ctf_align(uint8_t)
> + goto skip_exp;
> + }
> +
> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
> + int dst;
> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
> + for (dst = 0; dst < sizeof(long); dst++) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_exp;
> + }
> + }
> +#else
> + for (dst = sizeof(long); dst >= 0; dst--) {
> + ctf_user_integer_type(uint8_t,
> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
> + goto skip_exp;
> + }
> + }
> +#endif
> + }
> + skip_exp:
> + ;
> + )
> + )
> + )
> + ),
> + TP_code_post(
> + kfree(tp_locvar->fds_in);
> + kfree(tp_locvar->fds_out);
> + kfree(tp_locvar->fds_ex);
Thanks,
Mathieu
> + )
> +)
> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
> +
> #endif /* CREATE_SYSCALL_TABLE */
> --
> 1.9.1
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6
2016-04-29 18:13 ` Mathieu Desnoyers
@ 2016-04-29 18:25 ` Mathieu Desnoyers
0 siblings, 0 replies; 12+ messages in thread
From: Mathieu Desnoyers @ 2016-04-29 18:25 UTC (permalink / raw)
----- On Apr 29, 2016, at 2:13 PM, Mathieu Desnoyers mathieu.desnoyers at efficios.com wrote:
> ----- On Apr 22, 2016, at 8:16 PM, Julien Desfossez jdesfossez at efficios.com
> wrote:
>
>> Instead of extracting the user-space pointers of the 3 fd_set, we now
>> extract the bitmask of the FDs in the sets (in, out, ex) in the form of
>> an array of uint8_t (1024 FDs is the limit in the kernel).
>>
>> In this example, we select in input FDs 5 to 19 (0xFFFF0), it returns
>> that one FD is ready: FD 12 (0x1000).
>>
>> syscall_entry_select: {
>> n = 20,
>> _fdset_in_length = 3, fdset_in = [ [0] = 0xF0, [1] = 0xFF, [2] = 0xF ],
>> _fdset_out_length = 0, fdset_out = [ ],
>> _fdset_ex_length = 0, fdset_ex = [ ],
>> tvp = 0
>> }
>>
>> syscall_exit_select: {
>> ret = 1,
>> _fdset_in_length = 3, fdset_in = [ [0] = 0x0, [1] = 0x10, [2] = 0x0 ],
>> _fdset_out_length = 0, fdset_out = [ ],
>> _fdset_ex_length = 0, fdset_ex = [ ],
>> tvp = 0
>> }
>>
>> Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
>> ---
>> .../syscalls/headers/syscalls_pointers_override.h | 510 +++++++++++++++++++++
>> 1 file changed, 510 insertions(+)
>>
>> diff --git a/instrumentation/syscalls/headers/syscalls_pointers_override.h
>> b/instrumentation/syscalls/headers/syscalls_pointers_override.h
>> index bf5c632..ef4dc1c 100644
>> --- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
>> +++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
>> @@ -53,4 +53,514 @@ SC_LTTNG_TRACEPOINT_EVENT(pipe2,
>> )
>> )
>>
>> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64)
>> +#define OVERRIDE_32_select
>> +#define OVERRIDE_64_select
>> +SC_LTTNG_TRACEPOINT_EVENT_CODE(select,
>> + TP_PROTO(sc_exit(long ret,) int n, fd_set __user *inp, fd_set __user *outp,
>> + fd_set __user *exp, struct timeval *tvp),
>> + TP_ARGS(sc_exit(ret,) n, inp, outp, exp, tvp),
>> + TP_locvar(
>> + unsigned long *fds_in, *fds_out, *fds_ex;
>> + unsigned long nr_bytes, nr_ulong;
>> + unsigned int overflow;
>
> Change for uint8_t for overflow.
>
>> + ),
>> + TP_code_pre(
>> + sc_inout(
>> + {
>> + int err;
>> +
>> + tp_locvar->fds_in = NULL;
>> + tp_locvar->fds_out = NULL;
>> + tp_locvar->fds_ex = NULL;
>> +
>
> remove newline.
>
>> + tp_locvar->overflow = 0;
>> +
>> + sc_out(
>> + if (ret <= 0)
>> + goto error;
>> + )
>> +
>> + if (n <= 0)
>> + goto error;
>> +
>> + /* Limit atomic memory allocation to one page */
>> + if (DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) > PAGE_SIZE) {
>
> Put DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) into local variable.
>
>> + tp_locvar->nr_bytes = PAGE_SIZE;
>> + tp_locvar->nr_ulong = PAGE_SIZE / sizeof(unsigned long);
>> + /* Inform the user that we did not output everything. */
>> + tp_locvar->overflow = 1;
>> + } else {
>> + tp_locvar->nr_bytes = DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE);
>> + tp_locvar->nr_ulong = DIV_ROUND_UP((unsigned int) n,
>> + BITS_PER_BYTE * sizeof(unsigned long));
>> + }
>> + /* On error or bogus input, don't copy anything. */
>> + if (tp_locvar->nr_bytes > (__FD_SETSIZE / (8 * sizeof(uint8_t)))) {
>
> Replace 8 by BITS_PER_BYTE
>
> Move this check before the comparison with PAGE_SIZE.
> A "n" larger than 1023 is an error....
> Test on "n" rather than nr_bytes.
>
> nr_bytes will therefore never be over on page on linux.
> We could put a WARN_ON_ONCE() and goto error for it instead of the ceiling.
>
>
>> + goto error;
>> + }
>> +
>> + if (inp) {
>> + tp_locvar->fds_in = kmalloc(
>> + tp_locvar->nr_ulong * sizeof(unsigned long),
>> + GFP_ATOMIC);
>
>| GFP_NOWAIT as discussed.
>
>> + if (!tp_locvar->fds_in)
>> + goto error;
>> +
>> + err = lib_ring_buffer_copy_from_user_check_nofault(
>> + tp_locvar->fds_in, inp,
>> + tp_locvar->nr_ulong * sizeof(unsigned long));
>> + if (err != 0)
>> + goto error;
>> + }
>> + if (outp) {
>> + tp_locvar->fds_out = kmalloc(
>> + tp_locvar->nr_ulong * sizeof(unsigned long),
>> + GFP_ATOMIC);
>
> .....
>
>> + if (!tp_locvar->fds_out)
>> + goto error;
>> +
>> + err = lib_ring_buffer_copy_from_user_check_nofault(
>> + tp_locvar->fds_out, outp,
>> + tp_locvar->nr_ulong * sizeof(unsigned long));
>> + if (err != 0)
>> + goto error;
>> + }
>> + if (exp) {
>> + tp_locvar->fds_ex = kmalloc(
>> + tp_locvar->nr_ulong * sizeof(unsigned long),
>> + GFP_ATOMIC);
>
> .........
>
>> + if (!tp_locvar->fds_ex)
>> + goto error;
>> +
>> + err = lib_ring_buffer_copy_from_user_check_nofault(
>> + tp_locvar->fds_ex, exp,
>> + tp_locvar->nr_ulong * sizeof(unsigned long));
>> + if (err != 0)
>> + goto error;
>> + }
>> + goto end;
>> +
>> + error:
>> + tp_locvar->nr_bytes = 0;
>> + tp_locvar->nr_ulong = 0;
>> + end:
>> + /* bypass error: label at end of compound statement */
>
> Reword to /* Label at end of compound statement. */
>
>> + ;
>
> Mod line to:
>
> end: ; /* Label at end of compound statement. */
>
>> + }
>> + )
>> + ),
>> + TP_FIELDS(
>> + sc_exit(ctf_integer(long, ret, ret))
>> + sc_in(ctf_integer(int, n, n))
>> + sc_inout(ctf_integer(int, overflow, tp_locvar->overflow))
>
> uint8_t
>
>> + sc_inout(ctf_integer(struct timeval *, tvp, tvp))
>> +
>> + sc_inout(
>> + /* inp */
>> + ctf_custom_field(
>> + ctf_custom_type(
>> + .atype = atype_sequence,
>> + .u.sequence.length_type = __type_integer(
>> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
>
> uint8_t is enough. (1024/8=128)
>
>> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
>> + __BYTE_ORDER, 16, none),
>> + ),
>> + readfds,
>> + ctf_custom_code(
>> + unsigned int src;
>> + unsigned int nr_bytes_out = 0;
>> +
>> + if (inp) {
>> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
>
> uint8_t
>
>> + ctf_align(uint8_t)
>> + } else {
>> + ctf_integer_type(uint16_t, 0)
>
> uint8_t
>
>> + ctf_align(uint8_t)
>> + goto skip_inp;
>> + }
>> +
>> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
>> + int dst;
>> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
>> + for (dst = 0; dst < sizeof(long); dst++) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_inp;
>> + }
While technically correct, please do the check before
"writing" the field.
Move the check just before the ctf_user_integer_type(),
and post-increment it. (both little and big endian).
Mathieu
>> + }
>> +#else
>> + for (dst = sizeof(long); dst >= 0; dst--) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_inp;
>> + }
>> + }
>> +#endif
>> + }
>> + skip_inp:
>> + ;
>> + )
>
> 3 macros (nested) rather than cut n paste.
>
>> + )
>> + /* outp */
>> + ctf_custom_field(
>> + ctf_custom_type(
>> + .atype = atype_sequence,
>> + .u.sequence.length_type = __type_integer(
>> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
>> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
>> + __BYTE_ORDER, 16, none),
>> + ),
>> + writefds,
>> + ctf_custom_code(
>> + unsigned int src;
>> + unsigned int nr_bytes_out = 0;
>> +
>> + if (outp) {
>> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
>> + ctf_align(uint8_t)
>> + } else {
>> + ctf_integer_type(uint16_t, 0)
>> + ctf_align(uint8_t)
>> + goto skip_outp;
>> + }
>> +
>> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
>> + int dst;
>> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
>> + for (dst = 0; dst < sizeof(long); dst++) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_outp;
>> + }
>> + }
>> +#else
>> + for (dst = sizeof(long); dst >= 0; dst--) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_outp;
>> + }
>> + }
>> +#endif
>> + }
>> + skip_outp:
>> + ;
>> + )
>> + )
>> + /* exp */
>> + ctf_custom_field(
>> + ctf_custom_type(
>> + .atype = atype_sequence,
>> + .u.sequence.length_type = __type_integer(
>> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
>> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
>> + __BYTE_ORDER, 16, none),
>> + ),
>> + exceptfds,
>> + ctf_custom_code(
>> + unsigned int src;
>> + unsigned int nr_bytes_out = 0;
>> +
>> + if (exp) {
>> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
>> + ctf_align(uint8_t)
>> + } else {
>> + ctf_integer_type(uint16_t, 0)
>> + ctf_align(uint8_t)
>> + goto skip_exp;
>> + }
>> +
>> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
>> + int dst;
>> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
>> + for (dst = 0; dst < sizeof(long); dst++) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_exp;
>> + }
>> + }
>> +#else
>> + for (dst = sizeof(long); dst >= 0; dst--) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_exp;
>> + }
>> + }
>> +#endif
>> + }
>> + skip_exp:
>> + ;
>> + )
>> + )
>> + )
>> + ),
>> + TP_code_post(
>> + kfree(tp_locvar->fds_in);
>> + kfree(tp_locvar->fds_out);
>> + kfree(tp_locvar->fds_ex);
>> + )
>> +)
>> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) */
>> +
>> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64)
>> || defined(CONFIG_ARM)
>> +#define OVERRIDE_32_pselect6
>> +#define OVERRIDE_64_pselect6
>> +SC_LTTNG_TRACEPOINT_EVENT_CODE(pselect6,
>> + TP_PROTO(sc_exit(long ret,) int n, fd_set __user * inp, fd_set __user * outp,
>> + fd_set __user * exp, struct timeval * tvp, void * sig),
>> + TP_ARGS(sc_exit(ret,) n, inp, outp, exp, tvp, sig),
>> + TP_locvar(
>
> Please combine into a macro with select.
>
>> + unsigned long *fds_in, *fds_out, *fds_ex;
>> + unsigned long nr_bytes, nr_ulong;
>> + unsigned int overflow;
>> + ),
>> + TP_code_pre(
>> + sc_inout(
>> + {
>> + int err;
>> +
>> + tp_locvar->fds_in = NULL;
>> + tp_locvar->fds_out = NULL;
>> + tp_locvar->fds_ex = NULL;
>> +
>> + tp_locvar->overflow = 0;
>> +
>> + sc_out(
>> + if (ret <= 0)
>> + goto error;
>> + )
>> +
>> + if (n <= 0)
>> + goto error;
>> +
>> + /* Limit atomic memory allocation to one page */
>> + if (DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE) > PAGE_SIZE) {
>> + tp_locvar->nr_bytes = PAGE_SIZE;
>> + tp_locvar->nr_ulong = PAGE_SIZE / sizeof(unsigned long);
>> + /* Inform the user that we did not output everything. */
>> + tp_locvar->overflow = 1;
>> + } else {
>> + tp_locvar->nr_bytes = DIV_ROUND_UP((unsigned int) n, BITS_PER_BYTE);
>> + tp_locvar->nr_ulong = DIV_ROUND_UP((unsigned int) n,
>> + BITS_PER_BYTE * sizeof(unsigned long));
>> + }
>> + /* On error or bogus input, don't copy anything. */
>> + if (tp_locvar->nr_bytes > (__FD_SETSIZE / (8 * sizeof(uint8_t)))) {
>> + goto error;
>> + }
>> +
>> + if (inp) {
>> + tp_locvar->fds_in = kmalloc(
>> + tp_locvar->nr_ulong * sizeof(unsigned long),
>> + GFP_ATOMIC);
>> + if (!tp_locvar->fds_in)
>> + goto error;
>> +
>> + err = lib_ring_buffer_copy_from_user_check_nofault(
>> + tp_locvar->fds_in, inp,
>> + tp_locvar->nr_ulong * sizeof(unsigned long));
>> + if (err != 0)
>> + goto error;
>> + }
>> + if (outp) {
>> + tp_locvar->fds_out = kmalloc(
>> + tp_locvar->nr_ulong * sizeof(unsigned long),
>> + GFP_ATOMIC);
>> + if (!tp_locvar->fds_out)
>> + goto error;
>> +
>> + err = lib_ring_buffer_copy_from_user_check_nofault(
>> + tp_locvar->fds_out, outp,
>> + tp_locvar->nr_ulong * sizeof(unsigned long));
>> + if (err != 0)
>> + goto error;
>> + }
>> + if (exp) {
>> + tp_locvar->fds_ex = kmalloc(
>> + tp_locvar->nr_ulong * sizeof(unsigned long),
>> + GFP_ATOMIC);
>> + if (!tp_locvar->fds_ex)
>> + goto error;
>> +
>> + err = lib_ring_buffer_copy_from_user_check_nofault(
>> + tp_locvar->fds_ex, exp,
>> + tp_locvar->nr_ulong * sizeof(unsigned long));
>> + if (err != 0)
>> + goto error;
>> + }
>> + goto end;
>> +
>> + error:
>> + tp_locvar->nr_bytes = 0;
>> + tp_locvar->nr_ulong = 0;
>> + end:
>> + /* bypass error: label at end of compound statement */
>> + ;
>> + }
>> + )
>> + ),
>> + TP_FIELDS(
>> + sc_exit(ctf_integer(long, ret, ret))
>> + sc_in(ctf_integer(int, n, n))
>> + sc_in(ctf_integer(int, overflow, tp_locvar->overflow))
>> + sc_inout(ctf_integer(struct timeval *, tvp, tvp))
>> +
>> + sc_inout(
>> + /* inp */
>> + ctf_custom_field(
>> + ctf_custom_type(
>> + .atype = atype_sequence,
>> + .u.sequence.length_type = __type_integer(
>> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
>> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
>> + __BYTE_ORDER, 16, none),
>> + ),
>> + readfds,
>> + ctf_custom_code(
>> + unsigned int src;
>> + unsigned int nr_bytes_out = 0;
>> +
>> + if (inp) {
>> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
>> + ctf_align(uint8_t)
>> + } else {
>> + ctf_integer_type(uint16_t, 0)
>> + ctf_align(uint8_t)
>> + goto skip_inp;
>> + }
>> +
>> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
>> + int dst;
>> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
>> + for (dst = 0; dst < sizeof(long); dst++) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_inp;
>> + }
>> + }
>> +#else
>> + for (dst = sizeof(long); dst >= 0; dst--) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (inp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_inp;
>> + }
>> + }
>> +#endif
>> + }
>> + skip_inp:
>> + ;
>> + )
>> + )
>> + /* outp */
>> + ctf_custom_field(
>> + ctf_custom_type(
>> + .atype = atype_sequence,
>> + .u.sequence.length_type = __type_integer(
>> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
>> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
>> + __BYTE_ORDER, 16, none),
>> + ),
>> + writefds,
>> + ctf_custom_code(
>> + unsigned int src;
>> + unsigned int nr_bytes_out = 0;
>> +
>> + if (outp) {
>> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
>> + ctf_align(uint8_t)
>> + } else {
>> + ctf_integer_type(uint16_t, 0)
>> + ctf_align(uint8_t)
>> + goto skip_outp;
>> + }
>> +
>> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
>> + int dst;
>> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
>> + for (dst = 0; dst < sizeof(long); dst++) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_outp;
>> + }
>> + }
>> +#else
>> + for (dst = sizeof(long); dst >= 0; dst--) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (outp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_outp;
>> + }
>> + }
>> +#endif
>> + }
>> + skip_outp:
>> + ;
>> + )
>> + )
>> + /* exp */
>> + ctf_custom_field(
>> + ctf_custom_type(
>> + .atype = atype_sequence,
>> + .u.sequence.length_type = __type_integer(
>> + uint16_t, 0, 0, 0, __BYTE_ORDER, 10, none),
>> + .u.sequence.elem_type = __type_integer(uint8_t, 0, 0, 0,
>> + __BYTE_ORDER, 16, none),
>> + ),
>> + exceptfds,
>> + ctf_custom_code(
>> + unsigned int src;
>> + unsigned int nr_bytes_out = 0;
>> +
>> + if (exp) {
>> + ctf_integer_type(uint16_t, tp_locvar->nr_bytes)
>> + ctf_align(uint8_t)
>> + } else {
>> + ctf_integer_type(uint16_t, 0)
>> + ctf_align(uint8_t)
>> + goto skip_exp;
>> + }
>> +
>> + for (src = 0; src < tp_locvar->nr_ulong; src++) {
>> + int dst;
>> +#if (__BYTE_ORDER == __LITTLE_ENDIAN)
>> + for (dst = 0; dst < sizeof(long); dst++) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_exp;
>> + }
>> + }
>> +#else
>> + for (dst = sizeof(long); dst >= 0; dst--) {
>> + ctf_user_integer_type(uint8_t,
>> + ((uint8_t __user *) (exp->fds_bits + src))[dst]);
>> + if (++nr_bytes_out >= tp_locvar->nr_bytes) {
>> + goto skip_exp;
>> + }
>> + }
>> +#endif
>> + }
>> + skip_exp:
>> + ;
>> + )
>> + )
>> + )
>> + ),
>> + TP_code_post(
>> + kfree(tp_locvar->fds_in);
>> + kfree(tp_locvar->fds_out);
>> + kfree(tp_locvar->fds_ex);
>
> Thanks,
>
> Mathieu
>
>> + )
>> +)
>> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
>> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
>> +
>> #endif /* CREATE_SYSCALL_TABLE */
>> --
>> 1.9.1
>
> --
> Mathieu Desnoyers
> EfficiOS Inc.
> http://www.efficios.com
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 3/5] Extract the FDs and flags from poll and ppoll
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 3/5] Extract the FDs and flags from poll and ppoll Julien Desfossez
@ 2016-04-29 18:31 ` Mathieu Desnoyers
0 siblings, 0 replies; 12+ messages in thread
From: Mathieu Desnoyers @ 2016-04-29 18:31 UTC (permalink / raw)
----- On Apr 22, 2016, at 8:16 PM, Julien Desfossez jdesfossez at efficios.com wrote:
> Instead of printing the pointer address of the poll set, extract all the
> FDs and flags from the poll set. For now, we only output the
> standardized set of events to limit the verbosity of the output, we also
> extract the raw value. When we switch to CTF2 we will be able to hide
> unset fields and then we will extract all the fields.
>
> Here is an example of output with one FD:
> syscall_entry_poll: {
> timeout_msecs = -1, nfds = 1, fds_length = 1,
> fds = [
> [0] = { fd = 4, raw_events = 0x5, events = { POLLIN = 1, POLLPRI = 0,
> POLLOUT = 1, POLLERR = 0, POLLHUP = 0, padding = 0 } } ]
> }
>
> syscall_exit_poll: {
> ret = 1, nfds = 1, fds_length = 1,
> fds = [ [0] = { fd = 4, raw_events = 0x4, events = { POLLIN = 0,
> POLLPRI = 0, POLLOUT = 1, POLLERR = 0, POLLHUP = 0, padding = 0 } } ] }
>
> Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
> ---
> .../syscalls/headers/syscalls_pointers_override.h | 360 +++++++++++++++++++++
> 1 file changed, 360 insertions(+)
>
> diff --git a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> index ef4dc1c..6ade85c 100644
> --- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> +++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> @@ -563,4 +563,364 @@ SC_LTTNG_TRACEPOINT_EVENT_CODE(pselect6,
> )
> #endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
>
> +#ifndef ONCE_LTTNG_TRACE_POLL_H
> +#define ONCE_LTTNG_TRACE_POLL_H
> +
> +#define LTTNG_POLL_NRFLAGS (POLLNVAL + 1)
> +#define POLL_FLAGS_PADDING_SIZE (sizeof(uint8_t) * BITS_PER_BYTE) - \
> + ilog2(LTTNG_POLL_NRFLAGS - 1)
> +
> +/*
> + * Only extract the values specified by iBCS2 for now.
> + */
> +static struct lttng_event_field lttng_pollfd_flag_fields[] = {
> + [ilog2(POLLIN)] = {
> + .name = "POLLIN",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + [ilog2(POLLPRI)] = {
> + .name = "POLLPRI",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + [ilog2(POLLOUT)] = {
> + .name = "POLLOUT",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + [ilog2(POLLERR)] = {
> + .name = "POLLERR",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + [ilog2(POLLHUP)] = {
> + .name = "POLLHUP",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + [ilog2(POLLNVAL)] = {
> + .name = "POLLNVAL",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + [ilog2(LTTNG_POLL_NRFLAGS)] = {
> + .name = "padding",
> + .type = __type_integer(int, POLL_FLAGS_PADDING_SIZE, 1, 0,
> + __LITTLE_ENDIAN, 10, none),
> + },
> +};
> +
> +static struct lttng_event_field lttng_pollfd_fields[] = {
> + [0] = {
> + .name = "fd",
> + .type = __type_integer(int, 0, 0, 0, __BYTE_ORDER, 10, none),
> + },
> + [1] = {
> + .name = "raw_events",
> + .type = __type_integer(short, 0, 0, 0, __BYTE_ORDER, 16, none),
> + },
> + [2] = {
> + .name = "events",
> + .type = {
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(lttng_pollfd_flag_fields),
> + .u._struct.fields = lttng_pollfd_flag_fields,
> + }
> + },
> +};
> +
> +static struct lttng_type lttng_pollfd_elem = {
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(lttng_pollfd_fields),
> + .u._struct.fields = lttng_pollfd_fields,
> +};
> +#endif /* ONCE_LTTNG_TRACE_POLL_H */
> +
> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64)
> +#define OVERRIDE_32_poll
> +#define OVERRIDE_64_poll
> +SC_LTTNG_TRACEPOINT_EVENT_CODE(poll,
> + TP_PROTO(sc_exit(long ret,) struct pollfd __user * ufds,
> + unsigned int nfds, int timeout_msecs),
> + TP_ARGS(sc_exit(ret,) ufds, nfds, timeout_msecs),
> + TP_locvar(
> + unsigned int fds_length, fds_max_len;
> + struct pollfd *fds;
> + unsigned int alloc_fds;
Move alloc_fds to other uint.
> + unsigned int overflow;
becomes uint8_t.
> + ),
> + TP_code_pre(
> + BUILD_BUG_ON(((ARRAY_SIZE(lttng_pollfd_flag_fields) - 1) +
> + POLL_FLAGS_PADDING_SIZE) !=
> + sizeof(uint8_t) * BITS_PER_BYTE);
> + tp_locvar->fds = NULL;
> + tp_locvar->overflow = 0;
> +
> + sc_in(
> + if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
> + tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->fds_length = nfds;
> + tp_locvar->fds_max_len = nfds;
> + }
> + tp_locvar->alloc_fds = tp_locvar->fds_length * sizeof(struct pollfd);
> + )
> + /*
> + * On exit, the number of active FDs is determined by ret,
> + * nfds stays the same as the entry, but we only want to
> + * output the FDs that are relevant.
> + */
> + sc_out(
> + if (ret <= 0 || ret > nfds)
> + goto error;
> +
> + if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
> + tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->fds_length = ret;
> + tp_locvar->fds_max_len = nfds;
> + }
> + tp_locvar->alloc_fds = tp_locvar->fds_max_len * sizeof(struct pollfd);
> + )
> + {
> + int err;
> +
> + tp_locvar->fds = kmalloc(tp_locvar->alloc_fds, GFP_ATOMIC);
...........
> + if (!tp_locvar->fds)
> + goto error;
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds, ufds,
> + nfds * sizeof(struct pollfd));
> + if (err != 0)
> + goto error;
> + }
> + goto end;
> +
> + error:
> + tp_locvar->fds_length = 0;
> + tp_locvar->fds_max_len = 0;
> + end:
> + ;
> + ),
> + TP_FIELDS(
> + sc_exit(ctf_integer(long, ret, ret))
> + sc_in(ctf_integer(int, timeout_msecs, timeout_msecs))
> + sc_inout(ctf_integer(unsigned int, nfds, nfds))
> + sc_inout(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
> + sc_in(ctf_integer(int, overflow, tp_locvar->overflow))
uint8_t
> + sc_in(
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence_compound,
> + .u.sequence_compound.length_name = "fds_length",
> + .u.sequence_compound.elem_type = <tng_pollfd_elem,
> + ),
> + fds,
> + ctf_custom_code(
> + uint32_t i;
> +
> + ctf_align(int) /* Align on largest field in struct. */
> + for (i = 0; i < tp_locvar->fds_length; i++) {
> + ctf_integer_type(int, tp_locvar->fds[i].fd)
> + ctf_integer_type(short, tp_locvar->fds[i].events)
> + ctf_integer_bitfield_type(uint8_t,
> + (uint8_t) tp_locvar->fds[i].events)
> + }
> + )
> + )
> + )
> + sc_out(
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence_compound,
> + .u.sequence_compound.length_name = "fds_length",
> + .u.sequence_compound.elem_type = <tng_pollfd_elem,
> + ),
> + fds,
> + ctf_custom_code(
> + uint32_t i;
> + unsigned int nr = 0;
> +
> + ctf_align(int) /* Align on largest field in struct. */
> + /*
> + * Iterate over the complete array, but only output
> + * "ret" active FDs.
> + */
> + for (i = 0; i < tp_locvar->fds_max_len; i++) {
> + if (!tp_locvar->fds[i].revents)
> + continue;
> + if (++nr > tp_locvar->fds_length)
Change for: if (nr++ >= tp_locvar->fds_length)
> + break;
> + ctf_integer_type(int, tp_locvar->fds[i].fd)
> + ctf_integer_type(short, tp_locvar->fds[i].revents)
> + ctf_integer_bitfield_type(uint8_t,
> + (uint8_t) tp_locvar->fds[i].revents)
> + }
> + /*
> + * If there is a discrepancy between ret and the
> + * content of revents (e.g. caused by userspace corrupting
> + * the array from a concurrent thread), we have to output
> + * zeros to keep the trace readable.
> + */
> + for (i = nr; i < tp_locvar->fds_length - nr; i++) {
Remove the "- nr".
> + ctf_integer_type(int, 0)
> + ctf_integer_type(short, 0)
> + ctf_integer_bitfield_type(uint8_t, 0)
> + }
> + )
> + )
> + )
> + ),
> + TP_code_post(
> + kfree(tp_locvar->fds);
> + )
> +)
> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) */
> +
> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64)
> || defined(CONFIG_ARM)
> +#define OVERRIDE_32_ppoll
> +#define OVERRIDE_64_ppoll
> +SC_LTTNG_TRACEPOINT_EVENT_CODE(ppoll,
> + TP_PROTO(sc_exit(long ret,) struct pollfd __user * ufds,
> + unsigned int nfds, struct timespec * tsp, const sigset_t * sigmask, size_t
> sigsetsize),
> + TP_ARGS(sc_exit(ret,) ufds, nfds, tsp, sigmask, sigsetsize),
> + TP_locvar(
> + unsigned int fds_length, fds_max_len;
> + struct pollfd *fds;
> + unsigned int alloc_fds;
> + unsigned int overflow;
> + ),
> + TP_code_pre(
Use macros to remove code duplication.
Thanks,
Mathieu
> + BUILD_BUG_ON(((ARRAY_SIZE(lttng_pollfd_flag_fields) - 1) +
> + POLL_FLAGS_PADDING_SIZE) !=
> + sizeof(uint8_t) * BITS_PER_BYTE);
> + tp_locvar->fds = NULL;
> + tp_locvar->overflow = 0;
> +
> + sc_in(
> + if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
> + tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->fds_length = nfds;
> + tp_locvar->fds_max_len = nfds;
> + }
> + tp_locvar->alloc_fds = tp_locvar->fds_length * sizeof(struct pollfd);
> + )
> + /*
> + * On exit, the number of active FDs is determined by ret,
> + * nfds stays the same as the entry, but we only want to
> + * output the FDs that are relevant.
> + */
> + sc_out(
> + if (ret <= 0 || ret > nfds)
> + goto error;
> +
> + if (nfds * sizeof(struct pollfd) > PAGE_SIZE) {
> + tp_locvar->fds_length = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->fds_max_len = PAGE_SIZE / sizeof(struct pollfd);
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->fds_length = ret;
> + tp_locvar->fds_max_len = nfds;
> + }
> + tp_locvar->alloc_fds = tp_locvar->fds_max_len * sizeof(struct pollfd);
> + )
> + {
> + int err;
> +
> + tp_locvar->fds = kmalloc(tp_locvar->alloc_fds, GFP_ATOMIC);
> + if (!tp_locvar->fds)
> + goto error;
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->fds, ufds,
> + nfds * sizeof(struct pollfd));
> + if (err != 0)
> + goto error;
> + }
> + goto end;
> +
> + error:
> + tp_locvar->fds_length = 0;
> + tp_locvar->fds_max_len = 0;
> + end:
> + ;
> + ),
> + TP_FIELDS(
> + sc_exit(ctf_integer(long, ret, ret))
> + sc_in(ctf_integer(struct timespec *, tsp, tsp))
> + sc_in(ctf_integer(const sigset_t *, sigmask, sigmask))
> + sc_in(ctf_integer(size_t, sigsetsize, sigsetsize))
> + sc_inout(ctf_integer(unsigned int, nfds, nfds))
> + sc_inout(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
> + sc_inout(ctf_integer(int, overflow, tp_locvar->overflow))
> + sc_in(
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence_compound,
> + .u.sequence_compound.length_name = "fds_length",
> + .u.sequence_compound.elem_type = <tng_pollfd_elem,
> + ),
> + fds,
> + ctf_custom_code(
> + uint32_t i;
> +
> + ctf_align(int) /* Align on largest field in struct. */
> + for (i = 0; i < tp_locvar->fds_length; i++) {
> + ctf_integer_type(int, tp_locvar->fds[i].fd)
> + ctf_integer_type(short, tp_locvar->fds[i].events)
> + ctf_integer_bitfield_type(uint8_t,
> + (uint8_t) tp_locvar->fds[i].events)
> + }
> + )
> + )
> + )
> + sc_out(
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence_compound,
> + .u.sequence_compound.length_name = "fds_length",
> + .u.sequence_compound.elem_type = <tng_pollfd_elem,
> + ),
> + fds,
> + ctf_custom_code(
> + uint32_t i;
> + unsigned int nr = 0;
> +
> + ctf_align(int) /* Align on largest field in struct. */
> + /*
> + * Iterate over the complete array, but only output
> + * "ret" active FDs.
> + */
> + for (i = 0; i < tp_locvar->fds_max_len; i++) {
> + if (!tp_locvar->fds[i].revents)
> + continue;
> + if (++nr > tp_locvar->fds_length)
> + break;
> + ctf_integer_type(int, tp_locvar->fds[i].fd)
> + ctf_integer_type(short, tp_locvar->fds[i].revents)
> + ctf_integer_bitfield_type(uint8_t,
> + (uint8_t) tp_locvar->fds[i].revents)
> + }
> + /*
> + * If there is a discrepancy between ret and the
> + * content of revents (e.g. caused by userspace corrupting
> + * the array from a concurrent thread), we have to output
> + * zeros to keep the trace readable.
> + */
> + for (i = nr; i < tp_locvar->fds_length - nr; i++) {
> + ctf_integer_type(int, 0)
> + ctf_integer_type(short, 0)
> + ctf_integer_bitfield_type(uint8_t, 0)
> + }
> + )
> + )
> + )
> + ),
> + TP_code_post(
> + kfree(tp_locvar->fds);
> + )
> +)
> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
> +
> #endif /* CREATE_SYSCALL_TABLE */
> --
> 1.9.1
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 4/5] Extract the payload for epoll_ctl
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 4/5] Extract the payload for epoll_ctl Julien Desfossez
@ 2016-04-29 18:35 ` Mathieu Desnoyers
0 siblings, 0 replies; 12+ messages in thread
From: Mathieu Desnoyers @ 2016-04-29 18:35 UTC (permalink / raw)
----- On Apr 22, 2016, at 8:16 PM, Julien Desfossez jdesfossez at efficios.com wrote:
> Map the operation to its name (EPOLL_CTL_*), extract the standard event
> flags (EPOLL*) and output the data in two different formats: FD as an
> int in decimal, and u64 in hex. The less standard event flags are not
> extracted yet, but we extract the raw value in hex for more advanced
> analyses.
>
> Here is an example output:
> syscall_entry_epoll_ctl: {
> epfd = 4, op_enum = ( "EPOLL_CTL_ADD" : container = 1 ),
> fd = 0, event = { raw_events = 0x80000003,
> events = { EPOLLIN = 1, EPOLLPRI = 1, EPOLLOUT = 0, EPOLLERR = 0,
> padding = 0 },
> data_union = { u64 = 0x0, fd = 0 } }
> }
>
> syscall_exit_epoll_ctl: { ret = 0 }
>
> Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
> ---
> .../syscalls/headers/syscalls_pointers_override.h | 139 +++++++++++++++++++++
> 1 file changed, 139 insertions(+)
>
> diff --git a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> index 6ade85c..9fe0030 100644
> --- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> +++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> @@ -923,4 +923,143 @@ SC_LTTNG_TRACEPOINT_EVENT_CODE(ppoll,
> )
> #endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
>
> +#include <linux/eventpoll.h>
> +
> +SC_LTTNG_TRACEPOINT_ENUM(lttng_epoll_op,
> + TP_ENUM_VALUES(
> + ctf_enum_value("EPOLL_CTL_ADD", EPOLL_CTL_ADD)
> + ctf_enum_value("EPOLL_CTL_DEL", EPOLL_CTL_DEL)
> + ctf_enum_value("EPOLL_CTL_MOD", EPOLL_CTL_MOD)
> + )
> +)
> +
> +#ifndef ONCE_LTTNG_TRACE_EPOLL_CTL_H
> +#define ONCE_LTTNG_TRACE_EPOLL_CTL_H
> +
> +#define LTTNG_EPOLL_NRFLAGS (POLLHUP + 1)
> +#define EPOLL_FLAGS_PADDING_SIZE (sizeof(uint8_t) * BITS_PER_BYTE) -
> ilog2(LTTNG_EPOLL_NRFLAGS - 1)
newline with \ (too long)
> +
> +/*
> + * Only extract the values specified by iBCS2 for now.
> + */
> +static struct lttng_event_field lttng_epoll_ctl_events_fields[] = {
> + /* 0x0001 */
> + [ilog2(POLLIN)] = {
> + .name = "EPOLLIN",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + /* 0x0002 */
> + [ilog2(POLLPRI)] = {
> + .name = "EPOLLPRI",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + /* 0x0004 */
> + [ilog2(POLLOUT)] = {
> + .name = "EPOLLOUT",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + /* 0x0008 */
> + [ilog2(POLLERR)] = {
> + .name = "EPOLLERR",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + /* 0x0010 */
> + [ilog2(POLLHUP)] = {
> + .name = "EPOLLHUP",
> + .type = __type_integer(int, 1, 1, 0, __LITTLE_ENDIAN, 10, none),
> + },
> + [ilog2(LTTNG_EPOLL_NRFLAGS)] = {
> + .name = "padding",
> + .type = __type_integer(int, EPOLL_FLAGS_PADDING_SIZE, 1, 0,
> + __LITTLE_ENDIAN, 10, none),
> + },
> +
> +};
> +
> +static struct lttng_event_field lttng_epoll_data_fields[] = {
> + [0] = {
> + .name = "u64",
> + .type = __type_integer(uint64_t, 0, 0, 0, __BYTE_ORDER, 16, none),
> + },
> + [1] = {
> + .name = "fd",
> + .type = __type_integer(int, 0, 0, 0, __BYTE_ORDER, 10, none),
> + },
> +};
> +
> +static struct lttng_event_field epoll_ctl_fields[] = {
> + [0] = {
> + .name = "data_union",
> + .type = {
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_data_fields),
> + .u._struct.fields = lttng_epoll_data_fields,
> + }
> + },
> + [1] = {
> + .name = "raw_events",
> + .type = __type_integer(uint32_t, 0, 0, 0, __BYTE_ORDER, 16, none),
> + },
> + [2] = {
> + .name = "events",
> + .type = {
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_ctl_events_fields),
> + .u._struct.fields = lttng_epoll_ctl_events_fields,
> + }
> + },
> +};
> +#endif /* ONCE_LTTNG_TRACE_EPOLL_CTL_H */
> +
> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64)
> || defined(CONFIG_ARM)
> +#define OVERRIDE_32_epoll_ctl
> +#define OVERRIDE_64_epoll_ctl
> +SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_ctl,
> + TP_PROTO(sc_exit(long ret,) int epfd, int op, int fd,
> + struct epoll_event __user * uevent),
> + TP_ARGS(sc_exit(ret,) epfd, op, fd, uevent),
> + TP_locvar(
> + struct epoll_event event;
> + int err;
> + ),
> + TP_code_pre(
> + tp_locvar->err = lib_ring_buffer_copy_from_user_check_nofault(
> + &tp_locvar->event, uevent, sizeof(struct epoll_event));
> + ),
> + TP_FIELDS(
> + sc_exit(ctf_integer(long, ret, ret))
> + sc_in(ctf_integer(int, epfd, epfd))
> + sc_in(ctf_enum(lttng_epoll_op, int, op_enum, op))
> + sc_in(ctf_integer(int, fd, fd))
> + sc_in(
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(epoll_ctl_fields),
> + .u._struct.fields = epoll_ctl_fields,
> + ),
> + event,
> + ctf_custom_code(
> + ctf_align(uint64_t)
> + if (!tp_locvar->err) {
> + ctf_integer_type(uint64_t, tp_locvar->event.data)
> + ctf_integer_type(int, tp_locvar->event.data)
> + ctf_integer_bitfield_type(uint32_t,
> + cpu_to_le32(tp_locvar->event.events))
> + ctf_integer_bitfield_type(uint8_t,
> + (uint8_t) cpu_to_le32(tp_locvar->event.events))
remove cpu_to_le32.
Thanks,
Mathieu
> + } else {
> + ctf_integer_type(uint64_t, 0)
> + ctf_integer_type(int, 0)
> + ctf_integer_bitfield_type(uint32_t, 0)
> + ctf_integer_bitfield_type(uint8_t, 0)
> + }
> + )
> + )
> + )
> + ),
> + TP_code_post()
> +)
> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
> +
> #endif /* CREATE_SYSCALL_TABLE */
> --
> 1.9.1
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* [lttng-dev] [PATCH lttng-modules v5 5/5] Extract the payload of epoll_wait/epoll_pwait
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 5/5] Extract the payload of epoll_wait/epoll_pwait Julien Desfossez
@ 2016-04-29 18:45 ` Mathieu Desnoyers
0 siblings, 0 replies; 12+ messages in thread
From: Mathieu Desnoyers @ 2016-04-29 18:45 UTC (permalink / raw)
----- On Apr 22, 2016, at 8:16 PM, Julien Desfossez jdesfossez at efficios.com wrote:
> When epoll_wait returns, extract the content of the "events" field
> (events set and data payload).
>
> Here is an example output:
> syscall_entry_epoll_wait: { epfd = 3, maxevents = 32, timeout = 100 }
> syscall_exit_epoll_wait: { ret = 1, fds_length = 1,
> fds = [ [0] = { raw_events = 0x1,
> events = { EPOLLIN = 1, EPOLLPRI = 0, EPOLLOUT = 0, EPOLLERR = 0,
> padding = 0 },
> data_union = { u64 = 0x100000005, fd = 5 } } ]
> }
>
> Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
> ---
> .../syscalls/headers/syscalls_pointers_override.h | 234 +++++++++++++++++++++
> 1 file changed, 234 insertions(+)
>
> diff --git a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> index 9fe0030..68ba1a2 100644
> --- a/instrumentation/syscalls/headers/syscalls_pointers_override.h
> +++ b/instrumentation/syscalls/headers/syscalls_pointers_override.h
> @@ -1062,4 +1062,238 @@ SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_ctl,
> )
> #endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
>
> +#ifndef ONCE_LTTNG_TRACE_EPOLL_H
> +#define ONCE_LTTNG_TRACE_EPOLL_H
> +
> +static struct lttng_event_field lttng_epoll_wait_fields[] = {
> + [0] = {
> + .name = "data_union",
> + .type = {
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_data_fields),
> + .u._struct.fields = lttng_epoll_data_fields,
> + }
> + },
> + [1] = {
> + .name = "raw_events",
> + .type = __type_integer(uint32_t, 0, 0, 0, __BYTE_ORDER, 16, none),
> + },
> + [2] = {
> + .name = "events",
> + .type = {
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_ctl_events_fields),
> + .u._struct.fields = lttng_epoll_ctl_events_fields,
> + }
> + },
> +};
> +
> +static struct lttng_type lttng_epoll_wait_elem = {
> + .atype = atype_struct,
> + .u._struct.nr_fields = ARRAY_SIZE(lttng_epoll_wait_fields),
> + .u._struct.fields = lttng_epoll_wait_fields,
> +};
> +
> +#endif /* ONCE_LTTNG_TRACE_EPOLL_H */
> +
> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64)
> +#define OVERRIDE_32_epoll_wait
> +#define OVERRIDE_64_epoll_wait
> +SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_wait,
> + TP_PROTO(sc_exit(long ret,) int epfd, struct epoll_event __user * uevents,
> + int maxevents, int timeout),
> + TP_ARGS(sc_exit(ret,) epfd, uevents, maxevents, timeout),
> + TP_locvar(
> + sc_out(
> + unsigned int fds_length, overflow;
uint8_t for overflow.
> + struct epoll_event *events;
> + )
> + ),
> + TP_code_pre(
> + BUILD_BUG_ON(((ARRAY_SIZE(lttng_epoll_ctl_events_fields) - 1) +
> + EPOLL_FLAGS_PADDING_SIZE) !=
> + sizeof(uint8_t) * BITS_PER_BYTE);
> + sc_out({
> + int err;
> + unsigned long maxalloc;
> +
> + tp_locvar->fds_length = 0;
> + tp_locvar->events = NULL;
> + tp_locvar->overflow = 0;
> +
> + if (maxevents <= 0 || ret <= 0 || ret > maxevents)
> + goto skip_code;
> +
> + if ((maxevents * sizeof(struct epoll_event)) > PAGE_SIZE) {
> + maxalloc = PAGE_SIZE / sizeof(struct epoll_event);
> + if (ret > maxalloc) {
> + tp_locvar->fds_length = maxalloc;
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->fds_length = ret;
> + }
> + } else {
> + maxalloc = maxevents;
> + tp_locvar->fds_length = ret;
> + }
if ((maxevents * sizeof(struct epoll_event)) > PAGE_SIZE) {
maxalloc = PAGE_SIZE / sizeof(struct epoll_event);
} else {
maxalloc = maxevents;
}
if (ret > maxalloc) {
tp_locvar->fds_length = maxalloc;
tp_locvar->overflow = 1;
} else {
tp_locvar->fds_length = ret;
}
> +
> + tp_locvar->events = kmalloc(
> + maxalloc * sizeof(struct epoll_event),
> + GFP_ATOMIC);
.........
> + if (!tp_locvar->events) {
> + tp_locvar->fds_length = 0;
> + goto skip_code;
> + }
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->events, uevents,
> + maxevents * sizeof(struct epoll_event));
> + if (err != 0)
> + tp_locvar->fds_length = 0;
> + }
> + skip_code:
> + )
> + ),
> + TP_FIELDS(
> + sc_exit(ctf_integer(long, ret, ret))
> + sc_in(ctf_integer(int, epfd, epfd))
> + sc_in(ctf_integer(int, maxevents, maxevents))
> + sc_in(ctf_integer(int, timeout, timeout))
> + sc_out(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
> + sc_out(ctf_integer(int, overflow, tp_locvar->overflow))
uint8_t
> + sc_out(
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence_compound,
> + .u.sequence_compound.length_name =
> + "fds_length",
> + .u.sequence_compound.elem_type =
> + <tng_epoll_wait_elem,
> + ),
> + fds,
> + ctf_custom_code(
> + uint32_t i;
> +
> + ctf_align(uint64_t)
> + for (i = 0; i < tp_locvar->fds_length; i++) {
> + ctf_integer_type(uint64_t, tp_locvar->events[i].data)
> + ctf_integer_type(int, tp_locvar->events[i].data)
> + ctf_integer_bitfield_type(uint32_t,
> + cpu_to_le32(tp_locvar->events[i].events))
> + ctf_integer_bitfield_type(uint8_t,
> + (uint8_t) cpu_to_le32(tp_locvar->events[i].events))
remove cpu_to_le32.
> + }
> + )
> + )
> + )
> + ),
> + TP_code_post(
> + sc_out(
> + kfree(tp_locvar->events);
> + )
> + )
> +)
> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) */
> +
> +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) || defined(CONFIG_ARM64)
> || defined(CONFIG_ARM)
> +#define OVERRIDE_32_epoll_pwait
> +#define OVERRIDE_64_epoll_pwait
> +SC_LTTNG_TRACEPOINT_EVENT_CODE(epoll_pwait,
> + TP_PROTO(sc_exit(long ret,) int epfd, struct epoll_event __user * uevents,
> + int maxevents, int timeout, const sigset_t * sigmask, size_t sigsetsize),
> + TP_ARGS(sc_exit(ret,) epfd, uevents, maxevents, timeout, sigmask, sigsetsize),
> + TP_locvar(
> + sc_out(
> + unsigned int fds_length, overflow;
> + struct epoll_event *events;
use macros to remove code duplication.
Thanks,
Mathieu
> + )
> + ),
> + TP_code_pre(
> + BUILD_BUG_ON(((ARRAY_SIZE(lttng_epoll_ctl_events_fields) - 1) +
> + EPOLL_FLAGS_PADDING_SIZE) !=
> + sizeof(uint8_t) * BITS_PER_BYTE);
> + sc_out({
> + int err;
> + unsigned long maxalloc;
> +
> + tp_locvar->fds_length = 0;
> + tp_locvar->events = NULL;
> + tp_locvar->overflow = 0;
> +
> + if (maxevents <= 0 || ret <= 0 || ret > maxevents)
> + goto skip_code;
> +
> + if ((maxevents * sizeof(struct epoll_event)) > PAGE_SIZE) {
> + maxalloc = PAGE_SIZE / sizeof(struct epoll_event);
> + if (ret > maxalloc) {
> + tp_locvar->fds_length = maxalloc;
> + tp_locvar->overflow = 1;
> + } else {
> + tp_locvar->fds_length = ret;
> + }
> + } else {
> + maxalloc = maxevents;
> + tp_locvar->fds_length = ret;
> + }
> +
> + tp_locvar->events = kmalloc(
> + maxalloc * sizeof(struct epoll_event),
> + GFP_ATOMIC);
> + if (!tp_locvar->events) {
> + tp_locvar->fds_length = 0;
> + goto skip_code;
> + }
> +
> + err = lib_ring_buffer_copy_from_user_check_nofault(
> + tp_locvar->events, uevents,
> + maxevents * sizeof(struct epoll_event));
> + if (err != 0)
> + tp_locvar->fds_length = 0;
> + }
> + skip_code:
> + )
> + ),
> + TP_FIELDS(
> + sc_exit(ctf_integer(long, ret, ret))
> + sc_in(ctf_integer(int, epfd, epfd))
> + sc_in(ctf_integer(int, maxevents, maxevents))
> + sc_in(ctf_integer(int, timeout, timeout))
> + sc_in(ctf_integer(const sigset_t *, sigmask, sigmask))
> + sc_in(ctf_integer(size_t, sigsetsize, sigsetsize))
> + sc_out(ctf_integer(unsigned int, fds_length, tp_locvar->fds_length))
> + sc_out(ctf_integer(int, overflow, tp_locvar->overflow))
> + sc_out(
> + ctf_custom_field(
> + ctf_custom_type(
> + .atype = atype_sequence_compound,
> + .u.sequence_compound.length_name =
> + "fds_length",
> + .u.sequence_compound.elem_type =
> + <tng_epoll_wait_elem,
> + ),
> + fds,
> + ctf_custom_code(
> + uint32_t i;
> +
> + ctf_align(uint64_t)
> + for (i = 0; i < tp_locvar->fds_length; i++) {
> + ctf_integer_type(uint64_t, tp_locvar->events[i].data)
> + ctf_integer_type(int, tp_locvar->events[i].data)
> + ctf_integer_bitfield_type(uint32_t,
> + cpu_to_le32(tp_locvar->events[i].events))
> + ctf_integer_bitfield_type(uint8_t,
> + (uint8_t) cpu_to_le32(tp_locvar->events[i].events))
> + }
> + )
> + )
> + )
> + ),
> + TP_code_post(
> + sc_out(
> + kfree(tp_locvar->events);
> + )
> + )
> +)
> +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_X86_64) ||
> defined(CONFIG_ARM64) || defined(CONFIG_ARM) */
> +
> #endif /* CREATE_SYSCALL_TABLE */
> --
> 1.9.1
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2016-04-29 18:45 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-23 0:16 [lttng-dev] [PATCH lttng-modules v5 0/5] Extract payload from polling syscalls Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 1/5] Add ctf_integer_bitfield_type Julien Desfossez
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 2/5] Extract the FD sets in select and pselect6 Julien Desfossez
2016-04-25 20:42 ` Julien Desfossez
2016-04-29 18:13 ` Mathieu Desnoyers
2016-04-29 18:25 ` Mathieu Desnoyers
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 3/5] Extract the FDs and flags from poll and ppoll Julien Desfossez
2016-04-29 18:31 ` Mathieu Desnoyers
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 4/5] Extract the payload for epoll_ctl Julien Desfossez
2016-04-29 18:35 ` Mathieu Desnoyers
2016-04-23 0:16 ` [lttng-dev] [PATCH lttng-modules v5 5/5] Extract the payload of epoll_wait/epoll_pwait Julien Desfossez
2016-04-29 18:45 ` Mathieu Desnoyers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox