Skip to content

Commit 9178412

Browse files
mhiramatrostedt
authored andcommitted
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>
1 parent f451bc8 commit 9178412

File tree

4 files changed

+88
-110
lines changed

4 files changed

+88
-110
lines changed

kernel/trace/trace_kprobe.c

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -853,8 +853,8 @@ static const struct file_operations kprobe_profile_ops = {
853853
/* Kprobe specific fetch functions */
854854

855855
/* Return the length of string -- including null terminal byte */
856-
static nokprobe_inline void
857-
fetch_store_strlen(unsigned long addr, void *dest)
856+
static nokprobe_inline int
857+
fetch_store_strlen(unsigned long addr)
858858
{
859859
mm_segment_t old_fs;
860860
int ret, len = 0;
@@ -872,47 +872,40 @@ fetch_store_strlen(unsigned long addr, void *dest)
872872
pagefault_enable();
873873
set_fs(old_fs);
874874

875-
if (ret < 0) /* Failed to check the length */
876-
*(u32 *)dest = 0;
877-
else
878-
*(u32 *)dest = len;
875+
return (ret < 0) ? ret : len;
879876
}
880877

881878
/*
882879
* Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
883880
* length and relative data location.
884881
*/
885-
static nokprobe_inline void
886-
fetch_store_string(unsigned long addr, void *dest)
882+
static nokprobe_inline int
883+
fetch_store_string(unsigned long addr, void *dest, void *base)
887884
{
888-
int maxlen = get_rloc_len(*(u32 *)dest);
889-
u8 *dst = get_rloc_data(dest);
885+
int maxlen = get_loc_len(*(u32 *)dest);
886+
u8 *dst = get_loc_data(dest, base);
890887
long ret;
891888

892-
if (!maxlen)
893-
return;
894-
889+
if (unlikely(!maxlen))
890+
return -ENOMEM;
895891
/*
896892
* Try to get string again, since the string can be changed while
897893
* probing.
898894
*/
899895
ret = strncpy_from_unsafe(dst, (void *)addr, maxlen);
900896

901-
if (ret < 0) { /* Failed to fetch string */
902-
dst[0] = '\0';
903-
*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
904-
} else {
905-
*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
906-
}
897+
if (ret >= 0)
898+
*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
899+
return ret;
907900
}
908901

909902
/* Note that we don't verify it, since the code does not come from user space */
910903
static int
911904
process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
912-
bool pre)
905+
void *base)
913906
{
914907
unsigned long val;
915-
int ret;
908+
int ret = 0;
916909

917910
/* 1st stage: get value from context */
918911
switch (code->op) {
@@ -949,6 +942,13 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
949942
}
950943

951944
/* 3rd stage: store value to buffer */
945+
if (unlikely(!dest)) {
946+
if (code->op == FETCH_OP_ST_STRING)
947+
return fetch_store_strlen(val + code->offset);
948+
else
949+
return -EILSEQ;
950+
}
951+
952952
switch (code->op) {
953953
case FETCH_OP_ST_RAW:
954954
fetch_store_raw(val, code, dest);
@@ -957,10 +957,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
957957
probe_kernel_read(dest, (void *)val + code->offset, code->size);
958958
break;
959959
case FETCH_OP_ST_STRING:
960-
if (pre)
961-
fetch_store_strlen(val + code->offset, dest);
962-
else
963-
fetch_store_string(val + code->offset, dest);
960+
ret = fetch_store_string(val + code->offset, dest, base);
964961
break;
965962
default:
966963
return -EILSEQ;
@@ -973,7 +970,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
973970
code++;
974971
}
975972

976-
return code->op == FETCH_OP_END ? 0 : -EILSEQ;
973+
return code->op == FETCH_OP_END ? ret : -EILSEQ;
977974
}
978975
NOKPROBE_SYMBOL(process_fetch_insn)
979976

@@ -1008,7 +1005,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
10081005

10091006
entry = ring_buffer_event_data(event);
10101007
entry->ip = (unsigned long)tk->rp.kp.addr;
1011-
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
1008+
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
10121009

10131010
event_trigger_unlock_commit_regs(trace_file, buffer, event,
10141011
entry, irq_flags, pc, regs);
@@ -1057,7 +1054,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
10571054
entry = ring_buffer_event_data(event);
10581055
entry->func = (unsigned long)tk->rp.kp.addr;
10591056
entry->ret_ip = (unsigned long)ri->ret_addr;
1060-
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
1057+
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
10611058

10621059
event_trigger_unlock_commit_regs(trace_file, buffer, event,
10631060
entry, irq_flags, pc, regs);
@@ -1203,7 +1200,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
12031200

12041201
entry->ip = (unsigned long)tk->rp.kp.addr;
12051202
memset(&entry[1], 0, dsize);
1206-
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
1203+
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
12071204
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
12081205
head, NULL);
12091206
return 0;
@@ -1239,7 +1236,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
12391236

12401237
entry->func = (unsigned long)tk->rp.kp.addr;
12411238
entry->ret_ip = (unsigned long)ri->ret_addr;
1242-
store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
1239+
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
12431240
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
12441241
head, NULL);
12451242
}

kernel/trace/trace_probe.h

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,15 @@
5454
#define TP_FLAG_PROFILE 2
5555
#define TP_FLAG_REGISTERED 4
5656

57+
/* data_loc: data location, compatible with u32 */
58+
#define make_data_loc(len, offs) \
59+
(((u32)(len) << 16) | ((u32)(offs) & 0xffff))
60+
#define get_loc_len(dl) ((u32)(dl) >> 16)
61+
#define get_loc_offs(dl) ((u32)(dl) & 0xffff)
5762

58-
/* data_rloc: data relative location, compatible with u32 */
59-
#define make_data_rloc(len, roffs) \
60-
(((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
61-
#define get_rloc_len(dl) ((u32)(dl) >> 16)
62-
#define get_rloc_offs(dl) ((u32)(dl) & 0xffff)
63-
64-
/*
65-
* Convert data_rloc to data_loc:
66-
* data_rloc stores the offset from data_rloc itself, but data_loc
67-
* stores the offset from event entry.
68-
*/
69-
#define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs))
70-
71-
static nokprobe_inline void *get_rloc_data(u32 *dl)
72-
{
73-
return (u8 *)dl + get_rloc_offs(*dl);
74-
}
75-
76-
/* For data_loc conversion */
7763
static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
7864
{
79-
return (u8 *)ent + get_rloc_offs(*dl);
65+
return (u8 *)ent + get_loc_offs(*dl);
8066
}
8167

8268
/* Printing function type */

kernel/trace/trace_probe_tmpl.h

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,28 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
4848
}
4949
}
5050

51-
/* Define this for each callsite */
51+
/*
52+
* This must be defined for each callsite.
53+
* Return consumed dynamic data size (>= 0), or error (< 0).
54+
* If dest is NULL, don't store result and return required dynamic data size.
55+
*/
5256
static int
5357
process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
54-
void *dest, bool pre);
58+
void *dest, void *base);
5559

5660
/* Sum up total data length for dynamic arraies (strings) */
5761
static nokprobe_inline int
5862
__get_data_size(struct trace_probe *tp, struct pt_regs *regs)
5963
{
6064
struct probe_arg *arg;
61-
int i, ret = 0;
62-
u32 len;
65+
int i, len, ret = 0;
6366

6467
for (i = 0; i < tp->nr_args; i++) {
6568
arg = tp->args + i;
6669
if (unlikely(arg->dynamic)) {
67-
process_fetch_insn(arg->code, regs, &len, true);
68-
ret += len;
70+
len = process_fetch_insn(arg->code, regs, NULL, NULL);
71+
if (len > 0)
72+
ret += len;
6973
}
7074
}
7175

@@ -74,34 +78,26 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
7478

7579
/* Store the value of each argument */
7680
static nokprobe_inline void
77-
store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
78-
u8 *data, int maxlen)
81+
store_trace_args(void *data, struct trace_probe *tp, struct pt_regs *regs,
82+
int header_size, int maxlen)
7983
{
8084
struct probe_arg *arg;
81-
u32 end = tp->size;
82-
u32 *dl; /* Data (relative) location */
83-
int i;
85+
void *base = data - header_size;
86+
void *dyndata = data + tp->size;
87+
u32 *dl; /* Data location */
88+
int ret, i;
8489

8590
for (i = 0; i < tp->nr_args; i++) {
8691
arg = tp->args + i;
87-
if (unlikely(arg->dynamic)) {
88-
/*
89-
* First, we set the relative location and
90-
* maximum data length to *dl
91-
*/
92-
dl = (u32 *)(data + arg->offset);
93-
*dl = make_data_rloc(maxlen, end - arg->offset);
94-
/* Then try to fetch string or dynamic array data */
95-
process_fetch_insn(arg->code, regs, dl, false);
96-
/* Reduce maximum length */
97-
end += get_rloc_len(*dl);
98-
maxlen -= get_rloc_len(*dl);
99-
/* Trick here, convert data_rloc to data_loc */
100-
*dl = convert_rloc_to_loc(*dl, ent_size + arg->offset);
101-
} else
102-
/* Just fetching data normally */
103-
process_fetch_insn(arg->code, regs, data + arg->offset,
104-
false);
92+
dl = data + arg->offset;
93+
/* Point the dynamic data area if needed */
94+
if (unlikely(arg->dynamic))
95+
*dl = make_data_loc(maxlen, dyndata - base);
96+
ret = process_fetch_insn(arg->code, regs, dl, base);
97+
if (unlikely(ret < 0 && arg->dynamic))
98+
*dl = make_data_loc(0, dyndata - base);
99+
else
100+
dyndata += ret;
105101
}
106102
}
107103

kernel/trace/trace_uprobe.c

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -111,43 +111,38 @@ probe_user_read(void *dest, void *src, size_t size)
111111
* Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
112112
* length and relative data location.
113113
*/
114-
static nokprobe_inline void
115-
fetch_store_string(unsigned long addr, void *dest)
114+
static nokprobe_inline int
115+
fetch_store_string(unsigned long addr, void *dest, void *base)
116116
{
117117
long ret;
118-
u32 rloc = *(u32 *)dest;
119-
int maxlen = get_rloc_len(rloc);
120-
u8 *dst = get_rloc_data(dest);
118+
u32 loc = *(u32 *)dest;
119+
int maxlen = get_loc_len(loc);
120+
u8 *dst = get_loc_data(dest, base);
121121
void __user *src = (void __force __user *) addr;
122122

123-
if (!maxlen)
124-
return;
123+
if (unlikely(!maxlen))
124+
return -ENOMEM;
125125

126126
ret = strncpy_from_user(dst, src, maxlen);
127-
if (ret == maxlen)
128-
dst[--ret] = '\0';
129-
130-
if (ret < 0) { /* Failed to fetch string */
131-
((u8 *)get_rloc_data(dest))[0] = '\0';
132-
*(u32 *)dest = make_data_rloc(0, get_rloc_offs(rloc));
133-
} else {
134-
*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(rloc));
127+
if (ret >= 0) {
128+
if (ret == maxlen)
129+
dst[ret - 1] = '\0';
130+
*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
135131
}
132+
133+
return ret;
136134
}
137135

138136
/* Return the length of string -- including null terminal byte */
139-
static nokprobe_inline void
140-
fetch_store_strlen(unsigned long addr, void *dest)
137+
static nokprobe_inline int
138+
fetch_store_strlen(unsigned long addr)
141139
{
142140
int len;
143141
void __user *vaddr = (void __force __user *) addr;
144142

145143
len = strnlen_user(vaddr, MAX_STRING_SIZE);
146144

147-
if (len == 0 || len > MAX_STRING_SIZE) /* Failed to check length */
148-
*(u32 *)dest = 0;
149-
else
150-
*(u32 *)dest = len;
145+
return (len > MAX_STRING_SIZE) ? 0 : len;
151146
}
152147

153148
static unsigned long translate_user_vaddr(unsigned long file_offset)
@@ -164,10 +159,10 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
164159
/* Note that we don't verify it, since the code does not come from user space */
165160
static int
166161
process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
167-
bool pre)
162+
void *base)
168163
{
169164
unsigned long val;
170-
int ret;
165+
int ret = 0;
171166

172167
/* 1st stage: get value from context */
173168
switch (code->op) {
@@ -204,18 +199,22 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
204199
}
205200

206201
/* 3rd stage: store value to buffer */
202+
if (unlikely(!dest)) {
203+
if (code->op == FETCH_OP_ST_STRING)
204+
return fetch_store_strlen(val + code->offset);
205+
else
206+
return -EILSEQ;
207+
}
208+
207209
switch (code->op) {
208210
case FETCH_OP_ST_RAW:
209211
fetch_store_raw(val, code, dest);
210212
break;
211213
case FETCH_OP_ST_MEM:
212-
probe_user_read(dest, (void *)val + code->offset, code->size);
214+
probe_kernel_read(dest, (void *)val + code->offset, code->size);
213215
break;
214216
case FETCH_OP_ST_STRING:
215-
if (pre)
216-
fetch_store_strlen(val + code->offset, dest);
217-
else
218-
fetch_store_string(val + code->offset, dest);
217+
ret = fetch_store_string(val + code->offset, dest, base);
219218
break;
220219
default:
221220
return -EILSEQ;
@@ -228,7 +227,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
228227
code++;
229228
}
230229

231-
return code->op == FETCH_OP_END ? 0 : -EILSEQ;
230+
return code->op == FETCH_OP_END ? ret : -EILSEQ;
232231
}
233232
NOKPROBE_SYMBOL(process_fetch_insn)
234233

@@ -1300,7 +1299,7 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
13001299
esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
13011300

13021301
ucb = uprobe_buffer_get();
1303-
store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
1302+
store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
13041303

13051304
if (tu->tp.flags & TP_FLAG_TRACE)
13061305
ret |= uprobe_trace_func(tu, regs, ucb, dsize);
@@ -1335,7 +1334,7 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
13351334
esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
13361335

13371336
ucb = uprobe_buffer_get();
1338-
store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
1337+
store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
13391338

13401339
if (tu->tp.flags & TP_FLAG_TRACE)
13411340
uretprobe_trace_func(tu, func, regs, ucb, dsize);

0 commit comments

Comments
 (0)