tracing: Fix print_fields() and use best filter
cover tracing: Fix print_fields() and use best filter
When using user_events along with the new print_fields() functionality a few issues were discovered. When printing out fields, the __rel_loc field types were printing out the wrong array values. Also, user_events wasn't setting the best filter type, so __rel_loc data was marked as FILTER_OTHER vs FILTER_RDYN_STRING when chars were used. This resulted in strings being printed out as array of bytes vs a string.
After applying this series user_events will output strings correctly for __rel_loc via /sys/kernel/tracing/trace outputs. All events that utilize print_fields() will print the correct array/string for __data_loc and __rel_loc data, when it's enabled.
Beau Belgrave (2):
tracing/user_events: Set event filter_type from type
tracing: Fix print_fields() for __dyn_loc/__rel_loc
kernel/trace/trace_events_user.c | 3 +++ kernel/trace/trace_output.c | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-)
base-commit: 88fe1ec75fcb296579e05eaf3807da3ee83137e4
Signature · 1 line
2.25.1
PATCH 1/2 tracing/user_events: Set event filter_type from type
Users expect that events can be filtered by the kernel. User events currently sets all event fields as FILTER_OTHER which limits to binary filters only. When strings are being used, functionality is reduced.
Use filter_assign_type() to find the most appropriate filter type for each field in user events to ensure full kernel capabilities.
--- kernel/trace/trace_events_user.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/trace/trace_events_user.c +3 -0
@@ -918,6 +918,9 @@ static int user_event_add_field(struct user_event *user, const char *type, field->is_signed = is_signed; field->filter_type = filter_type; +if (filter_type ==FILTER_OTHER ) + field->filter_type =filter_assign_type (type); +list_add (&field->link, &user->fields);/*
Signature · 1 line
2.25.1
PATCH 2/2 tracing: Fix print_fields() for __dyn_loc/__rel_loc
In reply to Beau BelgraveBoth print_fields() and print_array() do not handle if dynamic data ends at the last byte of the payload for both __dyn_loc and __rel_loc field types. For __rel_loc, the offset was off by 4 bytes, leading to incorrect strings and data being printed out. In print_array() the buffer pos was missed from being advanced, which results in the first payload byte being used as the offset base instead of the field offset.
Advance __rel_loc offset by 4 to ensure correct offset and advance pos to the field offset to ensure correct data is displayed when printing arrays. Change >= to > when checking if data is in-bounds, since it's valid for dynamic data to include the last byte of the payload.
Example outputs for event format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:__rel_loc char text[]; offset:8; size:4; signed:1;Output before:tp_rel_loc: text=<OVERFLOW>
Output after:tp_rel_loc: text=Test
--- kernel/trace/trace_output.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
kernel/trace/trace_output.c +6 -4
@@ -819,13 +819,15 @@ static void print_array(struct trace_iterator *iter, void *pos, len = *(int *)pos >>16 ;if (field) - offset += field->offset; + offset += field->offset +sizeof (int ); -if (offset + len >= iter->ent_size) { +if (offset + len > iter->ent_size) {trace_seq_puts (&iter->seq,"<OVERFLOW>" );return ; } + pos = (void *)iter->ent + offset; +for (i =0 ; i < len; i++, pos++) {if (i)trace_seq_putc (&iter->seq,',' );
@@ -861,9 +863,9 @@ static void print_fields(struct trace_iterator *iter, struct trace_event_call *c len = *(int *)pos >>16 ;if (field->filter_type ==FILTER_RDYN_STRING ) - offset += field->offset; + offset += field->offset +sizeof (int ); -if (offset + len >= iter->ent_size) { +if (offset + len > iter->ent_size) {trace_seq_puts (&iter->seq,"<OVERFLOW>" );break ; }
Signature · 1 line
2.25.1