summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/trace/trace_events_hist.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 21cae42b54da..418ff27cbbaf 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -52,12 +52,28 @@ static u64 hist_field_string(struct hist_field *hist_field, void *event)
return (u64)(unsigned long)addr;
}
+static u64 hist_field_dynstring(struct hist_field *hist_field, void *event)
+{
+ u32 str_item = *(u32 *)(event + hist_field->field->offset);
+ int str_loc = str_item & 0xffff;
+ char *addr = (char *)(event + str_loc);
+
+ return (u64)(unsigned long)addr;
+}
+
+static u64 hist_field_pstring(struct hist_field *hist_field, void *event)
+{
+ char **addr = (char **)(event + hist_field->field->offset);
+
+ return (u64)(unsigned long)*addr;
+}
+
#define DEFINE_HIST_FIELD_FN(type) \
static u64 hist_field_##type(struct hist_field *hist_field, void *event)\
{ \
type *addr = (type *)(event + hist_field->field->offset); \
\
- return (u64)*addr; \
+ return (u64)(unsigned long)*addr; \
}
DEFINE_HIST_FIELD_FN(s64);
@@ -340,7 +356,13 @@ static struct hist_field *create_hist_field(struct ftrace_event_field *field,
if (is_string_field(field)) {
flags |= HIST_FIELD_FL_STRING;
- hist_field->fn = hist_field_string;
+
+ if (field->filter_type == FILTER_STATIC_STRING)
+ hist_field->fn = hist_field_string;
+ else if (field->filter_type == FILTER_DYN_STRING)
+ hist_field->fn = hist_field_dynstring;
+ else
+ hist_field->fn = hist_field_pstring;
} else {
hist_field->fn = select_value_fn(field->size,
field->is_signed);
@@ -508,7 +530,10 @@ static int create_key_field(struct hist_trigger_data *hist_data,
goto out;
}
- key_size = field->size;
+ if (is_string_field(field)) /* should be last key field */
+ key_size = HIST_KEY_SIZE_MAX - key_offset;
+ else
+ key_size = field->size;
}
hist_data->fields[key_idx] = create_hist_field(field, flags);
@@ -841,8 +866,24 @@ static void event_hist_trigger(struct event_trigger_data *data, void *rec)
key = (void *)&field_contents;
if (hist_data->n_keys > 1) {
+ /* ensure NULL-termination */
+ size_t size = key_field->size - 1;
+
+ if (key_field->flags & HIST_FIELD_FL_STRING) {
+ struct ftrace_event_field *field;
+
+ field = key_field->field;
+ if (field->filter_type == FILTER_DYN_STRING)
+ size = *(u32 *)(rec + field->offset) >> 16;
+ else if (field->filter_type == FILTER_PTR_STRING)
+ size = strlen(key);
+
+ if (size > key_field->size - 1)
+ size = key_field->size - 1;
+ }
+
memcpy(compound_key + key_field->offset, key,
- key_field->size);
+ size);
}
}
}