1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Traceprobe fetch helper inlines
6 static nokprobe_inline
void
7 fetch_store_raw(unsigned long val
, struct fetch_insn
*code
, void *buf
)
14 *(u16
*)buf
= (u16
)val
;
17 *(u32
*)buf
= (u32
)val
;
21 *(u64
*)buf
= (u64
)val
;
24 *(unsigned long *)buf
= val
;
28 static nokprobe_inline
void
29 fetch_apply_bitfield(struct fetch_insn
*code
, void *buf
)
31 switch (code
->basesize
) {
33 *(u8
*)buf
<<= code
->lshift
;
34 *(u8
*)buf
>>= code
->rshift
;
37 *(u16
*)buf
<<= code
->lshift
;
38 *(u16
*)buf
>>= code
->rshift
;
41 *(u32
*)buf
<<= code
->lshift
;
42 *(u32
*)buf
>>= code
->rshift
;
45 *(u64
*)buf
<<= code
->lshift
;
46 *(u64
*)buf
>>= code
->rshift
;
52 * These functions 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.
57 process_fetch_insn(struct fetch_insn
*code
, void *rec
, void *edata
,
58 void *dest
, void *base
);
59 static nokprobe_inline
int fetch_store_strlen(unsigned long addr
);
60 static nokprobe_inline
int
61 fetch_store_string(unsigned long addr
, void *dest
, void *base
);
62 static nokprobe_inline
int fetch_store_strlen_user(unsigned long addr
);
63 static nokprobe_inline
int
64 fetch_store_string_user(unsigned long addr
, void *dest
, void *base
);
65 static nokprobe_inline
int
66 probe_mem_read(void *dest
, void *src
, size_t size
);
67 static nokprobe_inline
int
68 probe_mem_read_user(void *dest
, void *src
, size_t size
);
70 static nokprobe_inline
int
71 fetch_store_symstrlen(unsigned long addr
)
73 char namebuf
[KSYM_SYMBOL_LEN
];
76 ret
= sprint_symbol(namebuf
, addr
);
84 * Fetch a null-terminated symbol string + offset. Caller MUST set *(u32 *)buf
85 * with max length and relative data location.
87 static nokprobe_inline
int
88 fetch_store_symstring(unsigned long addr
, void *dest
, void *base
)
90 int maxlen
= get_loc_len(*(u32
*)dest
);
93 if (unlikely(!maxlen
))
96 __dest
= get_loc_data(dest
, base
);
98 return sprint_symbol(__dest
, addr
);
101 /* common part of process_fetch_insn*/
102 static nokprobe_inline
int
103 process_common_fetch_insn(struct fetch_insn
*code
, unsigned long *val
)
107 *val
= code
->immediate
;
110 *val
= (unsigned long)current
->comm
;
113 *val
= (unsigned long)code
->data
;
121 /* From the 2nd stage, routine is same */
122 static nokprobe_inline
int
123 process_fetch_insn_bottom(struct fetch_insn
*code
, unsigned long val
,
124 void *dest
, void *base
)
126 struct fetch_insn
*s3
= NULL
;
127 int total
= 0, ret
= 0, i
= 0;
129 unsigned long lval
= val
;
132 /* 2nd stage: dereference memory if needed */
134 if (code
->op
== FETCH_OP_DEREF
) {
136 ret
= probe_mem_read(&val
, (void *)val
+ code
->offset
,
138 } else if (code
->op
== FETCH_OP_UDEREF
) {
140 ret
= probe_mem_read_user(&val
,
141 (void *)val
+ code
->offset
, sizeof(val
));
151 /* 3rd stage: store value to buffer */
152 if (unlikely(!dest
)) {
154 case FETCH_OP_ST_STRING
:
155 ret
= fetch_store_strlen(val
+ code
->offset
);
158 case FETCH_OP_ST_USTRING
:
159 ret
= fetch_store_strlen_user(val
+ code
->offset
);
162 case FETCH_OP_ST_SYMSTR
:
163 ret
= fetch_store_symstrlen(val
+ code
->offset
);
172 case FETCH_OP_ST_RAW
:
173 fetch_store_raw(val
, code
, dest
);
175 case FETCH_OP_ST_MEM
:
176 probe_mem_read(dest
, (void *)val
+ code
->offset
, code
->size
);
178 case FETCH_OP_ST_UMEM
:
179 probe_mem_read_user(dest
, (void *)val
+ code
->offset
, code
->size
);
181 case FETCH_OP_ST_STRING
:
183 ret
= fetch_store_string(val
+ code
->offset
, dest
, base
);
185 case FETCH_OP_ST_USTRING
:
187 ret
= fetch_store_string_user(val
+ code
->offset
, dest
, base
);
189 case FETCH_OP_ST_SYMSTR
:
191 ret
= fetch_store_symstring(val
+ code
->offset
, dest
, base
);
198 /* 4th stage: modify stored value if needed */
199 if (code
->op
== FETCH_OP_MOD_BF
) {
200 fetch_apply_bitfield(code
, dest
);
205 /* the last stage: Loop on array */
206 if (code
->op
== FETCH_OP_LP_ARRAY
) {
210 if (++i
< code
->param
) {
212 if (s3
->op
!= FETCH_OP_ST_STRING
&&
213 s3
->op
!= FETCH_OP_ST_USTRING
) {
219 val
= lval
+ sizeof(char *);
222 *(u32
*)dest
= update_data_loc(loc
, ret
);
230 return code
->op
== FETCH_OP_END
? ret
: -EILSEQ
;
233 /* Sum up total data length for dynamic arrays (strings) */
234 static nokprobe_inline
int
235 __get_data_size(struct trace_probe
*tp
, struct pt_regs
*regs
, void *edata
)
237 struct probe_arg
*arg
;
240 for (i
= 0; i
< tp
->nr_args
; i
++) {
242 if (unlikely(arg
->dynamic
)) {
243 len
= process_fetch_insn(arg
->code
, regs
, edata
, NULL
, NULL
);
252 /* Store the value of each argument */
253 static nokprobe_inline
void
254 store_trace_args(void *data
, struct trace_probe
*tp
, void *rec
, void *edata
,
255 int header_size
, int maxlen
)
257 struct probe_arg
*arg
;
258 void *base
= data
- header_size
;
259 void *dyndata
= data
+ tp
->size
;
260 u32
*dl
; /* Data location */
263 for (i
= 0; i
< tp
->nr_args
; i
++) {
265 dl
= data
+ arg
->offset
;
266 /* Point the dynamic data area if needed */
267 if (unlikely(arg
->dynamic
))
268 *dl
= make_data_loc(maxlen
, dyndata
- base
);
269 ret
= process_fetch_insn(arg
->code
, rec
, edata
, dl
, base
);
270 if (arg
->dynamic
&& likely(ret
> 0)) {