summaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_probe_tmpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_probe_tmpl.h')
-rw-r--r--kernel/trace/trace_probe_tmpl.h63
1 files changed, 55 insertions, 8 deletions
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
index b4075f3e3a29..5c56afc17cf8 100644
--- a/kernel/trace/trace_probe_tmpl.h
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -67,10 +67,15 @@ static nokprobe_inline int
process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
void *dest, void *base)
{
- int ret = 0;
+ struct fetch_insn *s3 = NULL;
+ int total = 0, ret = 0, i = 0;
+ u32 loc = 0;
+ unsigned long lval = val;
+stage2:
/* 2nd stage: dereference memory if needed */
while (code->op == FETCH_OP_DEREF) {
+ lval = val;
ret = probe_mem_read(&val, (void *)val + code->offset,
sizeof(val));
if (ret)
@@ -78,11 +83,15 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
code++;
}
+ s3 = code;
+stage3:
/* 3rd stage: store value to buffer */
if (unlikely(!dest)) {
- if (code->op == FETCH_OP_ST_STRING)
- return fetch_store_strlen(val + code->offset);
- else
+ if (code->op == FETCH_OP_ST_STRING) {
+ ret += fetch_store_strlen(val + code->offset);
+ code++;
+ goto array;
+ } else
return -EILSEQ;
}
@@ -94,6 +103,7 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
probe_mem_read(dest, (void *)val + code->offset, code->size);
break;
case FETCH_OP_ST_STRING:
+ loc = *(u32 *)dest;
ret = fetch_store_string(val + code->offset, dest, base);
break;
default:
@@ -107,6 +117,29 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
code++;
}
+array:
+ /* the last stage: Loop on array */
+ if (code->op == FETCH_OP_LP_ARRAY) {
+ total += ret;
+ if (++i < code->param) {
+ code = s3;
+ if (s3->op != FETCH_OP_ST_STRING) {
+ dest += s3->size;
+ val += s3->size;
+ goto stage3;
+ }
+ code--;
+ val = lval + sizeof(char *);
+ if (dest) {
+ dest += sizeof(u32);
+ *(u32 *)dest = update_data_loc(loc, ret);
+ }
+ goto stage2;
+ }
+ code++;
+ ret = total;
+ }
+
return code->op == FETCH_OP_END ? ret : -EILSEQ;
}
@@ -158,12 +191,26 @@ static inline int
print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
u8 *data, void *field)
{
- int i;
+ void *p;
+ int i, j;
for (i = 0; i < nr_args; i++) {
- trace_seq_printf(s, " %s=", args[i].name);
- if (!args[i].type->print(s, data + args[i].offset, field))
- return -ENOMEM;
+ struct probe_arg *a = args + i;
+
+ trace_seq_printf(s, " %s=", a->name);
+ if (likely(!a->count)) {
+ if (!a->type->print(s, data + a->offset, field))
+ return -ENOMEM;
+ continue;
+ }
+ trace_seq_putc(s, '{');
+ p = data + a->offset;
+ for (j = 0; j < a->count; j++) {
+ if (!a->type->print(s, p, field))
+ return -ENOMEM;
+ trace_seq_putc(s, j == a->count - 1 ? '}' : ',');
+ p += a->type->size;
+ }
}
return 0;
}