/* * These functions must be defined for each callsite. * Return consumed dynamic data size (>= 0), or error (< 0). * If dest is NULL, don't store result and return required dynamic data size.
*/ staticint
process_fetch_insn(struct fetch_insn *code, void *rec, void *edata, void *dest, void *base); static nokprobe_inline int fetch_store_strlen(unsignedlong addr); static nokprobe_inline int
fetch_store_string(unsignedlong addr, void *dest, void *base); static nokprobe_inline int fetch_store_strlen_user(unsignedlong addr); static nokprobe_inline int
fetch_store_string_user(unsignedlong addr, void *dest, void *base); static nokprobe_inline int
probe_mem_read(void *dest, void *src, size_t size); static nokprobe_inline int
probe_mem_read_user(void *dest, void *src, size_t size);
static nokprobe_inline int
fetch_store_symstrlen(unsignedlong addr)
{ char namebuf[KSYM_SYMBOL_LEN]; int ret;
ret = sprint_symbol(namebuf, addr); if (ret < 0) return 0;
return ret + 1;
}
/* * Fetch a null-terminated symbol string + offset. Caller MUST set *(u32 *)buf * with max length and relative data location.
*/ static nokprobe_inline int
fetch_store_symstring(unsignedlong addr, void *dest, void *base)
{ int maxlen = get_loc_len(*(u32 *)dest); void *__dest;
if (unlikely(!maxlen)) return -ENOMEM;
__dest = get_loc_data(dest, base);
return sprint_symbol(__dest, addr);
}
/* common part of process_fetch_insn*/ static nokprobe_inline int
process_common_fetch_insn(struct fetch_insn *code, unsignedlong *val)
{ switch (code->op) { case FETCH_OP_IMM:
*val = code->immediate; break; case FETCH_OP_COMM:
*val = (unsignedlong)current->comm; break; case FETCH_OP_DATA:
*val = (unsignedlong)code->data; break; default: return -EILSEQ;
} return 0;
}
/* From the 2nd stage, routine is same */ static nokprobe_inline int
process_fetch_insn_bottom(struct fetch_insn *code, unsignedlong val, void *dest, void *base)
{ struct fetch_insn *s3 = NULL; int total = 0, ret = 0, i = 0;
u32 loc = 0; unsignedlong lval = val;
stage2: /* 2nd stage: dereference memory if needed */ do { if (code->op == FETCH_OP_DEREF) {
lval = val;
ret = probe_mem_read(&val, (void *)val + code->offset, sizeof(val));
} elseif (code->op == FETCH_OP_UDEREF) {
lval = val;
ret = probe_mem_read_user(&val,
(void *)val + code->offset, sizeof(val));
} else break; if (ret) return ret;
code++;
} while (1);
s3 = code;
stage3: /* 3rd stage: store value to buffer */ if (unlikely(!dest)) { switch (code->op) { case FETCH_OP_ST_STRING:
ret = fetch_store_strlen(val + code->offset);
code++; goto array; case FETCH_OP_ST_USTRING:
ret = fetch_store_strlen_user(val + code->offset);
code++; goto array; case FETCH_OP_ST_SYMSTR:
ret = fetch_store_symstrlen(val + code->offset);
code++; goto array; default: return -EILSEQ;
}
}
switch (code->op) { case FETCH_OP_ST_RAW:
fetch_store_raw(val, code, dest); break; case FETCH_OP_ST_MEM:
probe_mem_read(dest, (void *)val + code->offset, code->size); break; case FETCH_OP_ST_UMEM:
probe_mem_read_user(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; case FETCH_OP_ST_USTRING:
loc = *(u32 *)dest;
ret = fetch_store_string_user(val + code->offset, dest, base); break; case FETCH_OP_ST_SYMSTR:
loc = *(u32 *)dest;
ret = fetch_store_symstring(val + code->offset, dest, base); break; default: return -EILSEQ;
}
code++;
/* 4th stage: modify stored value if needed */ if (code->op == FETCH_OP_MOD_BF) {
fetch_apply_bitfield(code, dest);
code++;
}
array: /* the last stage: Loop on array */ if (code->op == FETCH_OP_LP_ARRAY) { if (ret < 0)
ret = 0;
total += ret; if (++i < code->param) {
code = s3; if (s3->op != FETCH_OP_ST_STRING &&
s3->op != FETCH_OP_ST_USTRING) {
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;
}
/* Sum up total data length for dynamic arrays (strings) */ static nokprobe_inline int
__get_data_size(struct trace_probe *tp, void *regs, void *edata)
{ struct probe_arg *arg; int i, len, ret = 0;
for (i = 0; i < tp->nr_args; i++) {
arg = tp->args + i; if (unlikely(arg->dynamic)) {
len = process_fetch_insn(arg->code, regs, edata, NULL, NULL); if (len > 0)
ret += len;
}
}
return ret;
}
/* Store the value of each argument */ static nokprobe_inline void
store_trace_args(void *data, struct trace_probe *tp, void *rec, void *edata, int header_size, int maxlen)
{ struct probe_arg *arg; void *base = data - header_size; void *dyndata = data + tp->size;
u32 *dl; /* Data location */ int ret, i;
for (i = 0; i < tp->nr_args; i++) {
arg = tp->args + i;
dl = data + arg->offset; /* Point the dynamic data area if needed */ if (unlikely(arg->dynamic))
*dl = make_data_loc(maxlen, dyndata - base);
ret = process_fetch_insn(arg->code, rec, edata, dl, base); if (arg->dynamic && likely(ret > 0)) {
dyndata += ret;
maxlen -= ret;
}
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.