tracing: probeevent: Return consumed bytes of dynamic area
Cleanup string fetching routine so that returns the consumed bytes of dynamic area and store the string information as data_loc format instead of data_rloc. This simplifies the fetcharg loop. Link: http://lkml.kernel.org/r/152465874163.26224.12125143907501289031.stgit@devbox Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
这个提交包含在:

提交者
Steven Rostedt (VMware)

父节点
f451bc89d8
当前提交
9178412ddf
@@ -853,8 +853,8 @@ static const struct file_operations kprobe_profile_ops = {
|
||||
/* Kprobe specific fetch functions */
|
||||
|
||||
/* Return the length of string -- including null terminal byte */
|
||||
static nokprobe_inline void
|
||||
fetch_store_strlen(unsigned long addr, void *dest)
|
||||
static nokprobe_inline int
|
||||
fetch_store_strlen(unsigned long addr)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
int ret, len = 0;
|
||||
@@ -872,47 +872,40 @@ fetch_store_strlen(unsigned long addr, void *dest)
|
||||
pagefault_enable();
|
||||
set_fs(old_fs);
|
||||
|
||||
if (ret < 0) /* Failed to check the length */
|
||||
*(u32 *)dest = 0;
|
||||
else
|
||||
*(u32 *)dest = len;
|
||||
return (ret < 0) ? ret : len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
|
||||
* length and relative data location.
|
||||
*/
|
||||
static nokprobe_inline void
|
||||
fetch_store_string(unsigned long addr, void *dest)
|
||||
static nokprobe_inline int
|
||||
fetch_store_string(unsigned long addr, void *dest, void *base)
|
||||
{
|
||||
int maxlen = get_rloc_len(*(u32 *)dest);
|
||||
u8 *dst = get_rloc_data(dest);
|
||||
int maxlen = get_loc_len(*(u32 *)dest);
|
||||
u8 *dst = get_loc_data(dest, base);
|
||||
long ret;
|
||||
|
||||
if (!maxlen)
|
||||
return;
|
||||
|
||||
if (unlikely(!maxlen))
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Try to get string again, since the string can be changed while
|
||||
* probing.
|
||||
*/
|
||||
ret = strncpy_from_unsafe(dst, (void *)addr, maxlen);
|
||||
|
||||
if (ret < 0) { /* Failed to fetch string */
|
||||
dst[0] = '\0';
|
||||
*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
|
||||
} else {
|
||||
*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
|
||||
}
|
||||
if (ret >= 0)
|
||||
*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Note that we don't verify it, since the code does not come from user space */
|
||||
static int
|
||||
process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
|
||||
bool pre)
|
||||
void *base)
|
||||
{
|
||||
unsigned long val;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/* 1st stage: get value from context */
|
||||
switch (code->op) {
|
||||
@@ -949,6 +942,13 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
|
||||
}
|
||||
|
||||
/* 3rd stage: store value to buffer */
|
||||
if (unlikely(!dest)) {
|
||||
if (code->op == FETCH_OP_ST_STRING)
|
||||
return fetch_store_strlen(val + code->offset);
|
||||
else
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
switch (code->op) {
|
||||
case FETCH_OP_ST_RAW:
|
||||
fetch_store_raw(val, code, dest);
|
||||
@@ -957,10 +957,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
|
||||
probe_kernel_read(dest, (void *)val + code->offset, code->size);
|
||||
break;
|
||||
case FETCH_OP_ST_STRING:
|
||||
if (pre)
|
||||
fetch_store_strlen(val + code->offset, dest);
|
||||
else
|
||||
fetch_store_string(val + code->offset, dest);
|
||||
ret = fetch_store_string(val + code->offset, dest, base);
|
||||
break;
|
||||
default:
|
||||
return -EILSEQ;
|
||||
@@ -973,7 +970,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
|
||||
code++;
|
||||
}
|
||||
|
||||
return code->op == FETCH_OP_END ? 0 : -EILSEQ;
|
||||
return code->op == FETCH_OP_END ? ret : -EILSEQ;
|
||||
}
|
||||
NOKPROBE_SYMBOL(process_fetch_insn)
|
||||
|
||||
@@ -1008,7 +1005,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
|
||||
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = (unsigned long)tk->rp.kp.addr;
|
||||
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
|
||||
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
|
||||
|
||||
event_trigger_unlock_commit_regs(trace_file, buffer, event,
|
||||
entry, irq_flags, pc, regs);
|
||||
@@ -1057,7 +1054,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->func = (unsigned long)tk->rp.kp.addr;
|
||||
entry->ret_ip = (unsigned long)ri->ret_addr;
|
||||
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
|
||||
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
|
||||
|
||||
event_trigger_unlock_commit_regs(trace_file, buffer, event,
|
||||
entry, irq_flags, pc, regs);
|
||||
@@ -1203,7 +1200,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
|
||||
|
||||
entry->ip = (unsigned long)tk->rp.kp.addr;
|
||||
memset(&entry[1], 0, dsize);
|
||||
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
|
||||
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
|
||||
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
|
||||
head, NULL);
|
||||
return 0;
|
||||
@@ -1239,7 +1236,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
|
||||
|
||||
entry->func = (unsigned long)tk->rp.kp.addr;
|
||||
entry->ret_ip = (unsigned long)ri->ret_addr;
|
||||
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
|
||||
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
|
||||
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
|
||||
head, NULL);
|
||||
}
|
||||
|
在新工单中引用
屏蔽一个用户