| .. | .. |
|---|
| 13 | 13 | |
|---|
| 14 | 14 | #include "trace_probe.h" |
|---|
| 15 | 15 | |
|---|
| 16 | | -const char *reserved_field_names[] = { |
|---|
| 16 | +#undef C |
|---|
| 17 | +#define C(a, b) b |
|---|
| 18 | + |
|---|
| 19 | +static const char *trace_probe_err_text[] = { ERRORS }; |
|---|
| 20 | + |
|---|
| 21 | +static const char *reserved_field_names[] = { |
|---|
| 17 | 22 | "common_type", |
|---|
| 18 | 23 | "common_flags", |
|---|
| 19 | 24 | "common_preempt_count", |
|---|
| .. | .. |
|---|
| 26 | 31 | |
|---|
| 27 | 32 | /* Printing in basic type function template */ |
|---|
| 28 | 33 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt) \ |
|---|
| 29 | | -int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name, \ |
|---|
| 30 | | - void *data, void *ent) \ |
|---|
| 34 | +int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\ |
|---|
| 31 | 35 | { \ |
|---|
| 32 | | - trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ |
|---|
| 36 | + trace_seq_printf(s, fmt, *(type *)data); \ |
|---|
| 33 | 37 | return !trace_seq_has_overflowed(s); \ |
|---|
| 34 | 38 | } \ |
|---|
| 35 | | -const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; \ |
|---|
| 36 | | -NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname)); |
|---|
| 39 | +const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; |
|---|
| 37 | 40 | |
|---|
| 38 | 41 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8, u8, "%u") |
|---|
| 39 | 42 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u") |
|---|
| .. | .. |
|---|
| 48 | 51 | DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") |
|---|
| 49 | 52 | DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") |
|---|
| 50 | 53 | |
|---|
| 54 | +int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent) |
|---|
| 55 | +{ |
|---|
| 56 | + trace_seq_printf(s, "%pS", (void *)*(unsigned long *)data); |
|---|
| 57 | + return !trace_seq_has_overflowed(s); |
|---|
| 58 | +} |
|---|
| 59 | +const char PRINT_TYPE_FMT_NAME(symbol)[] = "%pS"; |
|---|
| 60 | + |
|---|
| 51 | 61 | /* Print type function for string type */ |
|---|
| 52 | | -int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name, |
|---|
| 53 | | - void *data, void *ent) |
|---|
| 62 | +int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent) |
|---|
| 54 | 63 | { |
|---|
| 55 | 64 | int len = *(u32 *)data >> 16; |
|---|
| 56 | 65 | |
|---|
| 57 | 66 | if (!len) |
|---|
| 58 | | - trace_seq_printf(s, " %s=(fault)", name); |
|---|
| 67 | + trace_seq_puts(s, "(fault)"); |
|---|
| 59 | 68 | else |
|---|
| 60 | | - trace_seq_printf(s, " %s=\"%s\"", name, |
|---|
| 69 | + trace_seq_printf(s, "\"%s\"", |
|---|
| 61 | 70 | (const char *)get_loc_data(data, ent)); |
|---|
| 62 | 71 | return !trace_seq_has_overflowed(s); |
|---|
| 63 | 72 | } |
|---|
| 64 | | -NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string)); |
|---|
| 65 | 73 | |
|---|
| 66 | 74 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
|---|
| 67 | 75 | |
|---|
| 68 | | -#define CHECK_FETCH_FUNCS(method, fn) \ |
|---|
| 69 | | - (((FETCH_FUNC_NAME(method, u8) == fn) || \ |
|---|
| 70 | | - (FETCH_FUNC_NAME(method, u16) == fn) || \ |
|---|
| 71 | | - (FETCH_FUNC_NAME(method, u32) == fn) || \ |
|---|
| 72 | | - (FETCH_FUNC_NAME(method, u64) == fn) || \ |
|---|
| 73 | | - (FETCH_FUNC_NAME(method, string) == fn) || \ |
|---|
| 74 | | - (FETCH_FUNC_NAME(method, string_size) == fn)) \ |
|---|
| 75 | | - && (fn != NULL)) |
|---|
| 76 | +/* Fetch type information table */ |
|---|
| 77 | +static const struct fetch_type probe_fetch_types[] = { |
|---|
| 78 | + /* Special types */ |
|---|
| 79 | + __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, |
|---|
| 80 | + "__data_loc char[]"), |
|---|
| 81 | + __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, |
|---|
| 82 | + "__data_loc char[]"), |
|---|
| 83 | + /* Basic types */ |
|---|
| 84 | + ASSIGN_FETCH_TYPE(u8, u8, 0), |
|---|
| 85 | + ASSIGN_FETCH_TYPE(u16, u16, 0), |
|---|
| 86 | + ASSIGN_FETCH_TYPE(u32, u32, 0), |
|---|
| 87 | + ASSIGN_FETCH_TYPE(u64, u64, 0), |
|---|
| 88 | + ASSIGN_FETCH_TYPE(s8, u8, 1), |
|---|
| 89 | + ASSIGN_FETCH_TYPE(s16, u16, 1), |
|---|
| 90 | + ASSIGN_FETCH_TYPE(s32, u32, 1), |
|---|
| 91 | + ASSIGN_FETCH_TYPE(s64, u64, 1), |
|---|
| 92 | + ASSIGN_FETCH_TYPE_ALIAS(x8, u8, u8, 0), |
|---|
| 93 | + ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0), |
|---|
| 94 | + ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0), |
|---|
| 95 | + ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0), |
|---|
| 96 | + ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0), |
|---|
| 76 | 97 | |
|---|
| 77 | | -/* Data fetch function templates */ |
|---|
| 78 | | -#define DEFINE_FETCH_reg(type) \ |
|---|
| 79 | | -void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest) \ |
|---|
| 80 | | -{ \ |
|---|
| 81 | | - *(type *)dest = (type)regs_get_register(regs, \ |
|---|
| 82 | | - (unsigned int)((unsigned long)offset)); \ |
|---|
| 83 | | -} \ |
|---|
| 84 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type)); |
|---|
| 85 | | -DEFINE_BASIC_FETCH_FUNCS(reg) |
|---|
| 86 | | -/* No string on the register */ |
|---|
| 87 | | -#define fetch_reg_string NULL |
|---|
| 88 | | -#define fetch_reg_string_size NULL |
|---|
| 89 | | - |
|---|
| 90 | | -#define DEFINE_FETCH_retval(type) \ |
|---|
| 91 | | -void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ |
|---|
| 92 | | - void *dummy, void *dest) \ |
|---|
| 93 | | -{ \ |
|---|
| 94 | | - *(type *)dest = (type)regs_return_value(regs); \ |
|---|
| 95 | | -} \ |
|---|
| 96 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type)); |
|---|
| 97 | | -DEFINE_BASIC_FETCH_FUNCS(retval) |
|---|
| 98 | | -/* No string on the retval */ |
|---|
| 99 | | -#define fetch_retval_string NULL |
|---|
| 100 | | -#define fetch_retval_string_size NULL |
|---|
| 101 | | - |
|---|
| 102 | | -/* Dereference memory access function */ |
|---|
| 103 | | -struct deref_fetch_param { |
|---|
| 104 | | - struct fetch_param orig; |
|---|
| 105 | | - long offset; |
|---|
| 106 | | - fetch_func_t fetch; |
|---|
| 107 | | - fetch_func_t fetch_size; |
|---|
| 98 | + ASSIGN_FETCH_TYPE_END |
|---|
| 108 | 99 | }; |
|---|
| 109 | 100 | |
|---|
| 110 | | -#define DEFINE_FETCH_deref(type) \ |
|---|
| 111 | | -void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ |
|---|
| 112 | | - void *data, void *dest) \ |
|---|
| 113 | | -{ \ |
|---|
| 114 | | - struct deref_fetch_param *dprm = data; \ |
|---|
| 115 | | - unsigned long addr; \ |
|---|
| 116 | | - call_fetch(&dprm->orig, regs, &addr); \ |
|---|
| 117 | | - if (addr) { \ |
|---|
| 118 | | - addr += dprm->offset; \ |
|---|
| 119 | | - dprm->fetch(regs, (void *)addr, dest); \ |
|---|
| 120 | | - } else \ |
|---|
| 121 | | - *(type *)dest = 0; \ |
|---|
| 122 | | -} \ |
|---|
| 123 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type)); |
|---|
| 124 | | -DEFINE_BASIC_FETCH_FUNCS(deref) |
|---|
| 125 | | -DEFINE_FETCH_deref(string) |
|---|
| 126 | | - |
|---|
| 127 | | -void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, |
|---|
| 128 | | - void *data, void *dest) |
|---|
| 129 | | -{ |
|---|
| 130 | | - struct deref_fetch_param *dprm = data; |
|---|
| 131 | | - unsigned long addr; |
|---|
| 132 | | - |
|---|
| 133 | | - call_fetch(&dprm->orig, regs, &addr); |
|---|
| 134 | | - if (addr && dprm->fetch_size) { |
|---|
| 135 | | - addr += dprm->offset; |
|---|
| 136 | | - dprm->fetch_size(regs, (void *)addr, dest); |
|---|
| 137 | | - } else |
|---|
| 138 | | - *(string_size *)dest = 0; |
|---|
| 139 | | -} |
|---|
| 140 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size)); |
|---|
| 141 | | - |
|---|
| 142 | | -static void update_deref_fetch_param(struct deref_fetch_param *data) |
|---|
| 143 | | -{ |
|---|
| 144 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
|---|
| 145 | | - update_deref_fetch_param(data->orig.data); |
|---|
| 146 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
|---|
| 147 | | - update_symbol_cache(data->orig.data); |
|---|
| 148 | | -} |
|---|
| 149 | | -NOKPROBE_SYMBOL(update_deref_fetch_param); |
|---|
| 150 | | - |
|---|
| 151 | | -static void free_deref_fetch_param(struct deref_fetch_param *data) |
|---|
| 152 | | -{ |
|---|
| 153 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
|---|
| 154 | | - free_deref_fetch_param(data->orig.data); |
|---|
| 155 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
|---|
| 156 | | - free_symbol_cache(data->orig.data); |
|---|
| 157 | | - kfree(data); |
|---|
| 158 | | -} |
|---|
| 159 | | -NOKPROBE_SYMBOL(free_deref_fetch_param); |
|---|
| 160 | | - |
|---|
| 161 | | -/* Bitfield fetch function */ |
|---|
| 162 | | -struct bitfield_fetch_param { |
|---|
| 163 | | - struct fetch_param orig; |
|---|
| 164 | | - unsigned char hi_shift; |
|---|
| 165 | | - unsigned char low_shift; |
|---|
| 166 | | -}; |
|---|
| 167 | | - |
|---|
| 168 | | -#define DEFINE_FETCH_bitfield(type) \ |
|---|
| 169 | | -void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ |
|---|
| 170 | | - void *data, void *dest) \ |
|---|
| 171 | | -{ \ |
|---|
| 172 | | - struct bitfield_fetch_param *bprm = data; \ |
|---|
| 173 | | - type buf = 0; \ |
|---|
| 174 | | - call_fetch(&bprm->orig, regs, &buf); \ |
|---|
| 175 | | - if (buf) { \ |
|---|
| 176 | | - buf <<= bprm->hi_shift; \ |
|---|
| 177 | | - buf >>= bprm->low_shift; \ |
|---|
| 178 | | - } \ |
|---|
| 179 | | - *(type *)dest = buf; \ |
|---|
| 180 | | -} \ |
|---|
| 181 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type)); |
|---|
| 182 | | -DEFINE_BASIC_FETCH_FUNCS(bitfield) |
|---|
| 183 | | -#define fetch_bitfield_string NULL |
|---|
| 184 | | -#define fetch_bitfield_string_size NULL |
|---|
| 185 | | - |
|---|
| 186 | | -static void |
|---|
| 187 | | -update_bitfield_fetch_param(struct bitfield_fetch_param *data) |
|---|
| 188 | | -{ |
|---|
| 189 | | - /* |
|---|
| 190 | | - * Don't check the bitfield itself, because this must be the |
|---|
| 191 | | - * last fetch function. |
|---|
| 192 | | - */ |
|---|
| 193 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
|---|
| 194 | | - update_deref_fetch_param(data->orig.data); |
|---|
| 195 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
|---|
| 196 | | - update_symbol_cache(data->orig.data); |
|---|
| 197 | | -} |
|---|
| 198 | | - |
|---|
| 199 | | -static void |
|---|
| 200 | | -free_bitfield_fetch_param(struct bitfield_fetch_param *data) |
|---|
| 201 | | -{ |
|---|
| 202 | | - /* |
|---|
| 203 | | - * Don't check the bitfield itself, because this must be the |
|---|
| 204 | | - * last fetch function. |
|---|
| 205 | | - */ |
|---|
| 206 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
|---|
| 207 | | - free_deref_fetch_param(data->orig.data); |
|---|
| 208 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
|---|
| 209 | | - free_symbol_cache(data->orig.data); |
|---|
| 210 | | - |
|---|
| 211 | | - kfree(data); |
|---|
| 212 | | -} |
|---|
| 213 | | - |
|---|
| 214 | | -void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs, |
|---|
| 215 | | - void *data, void *dest) |
|---|
| 216 | | -{ |
|---|
| 217 | | - int maxlen = get_rloc_len(*(u32 *)dest); |
|---|
| 218 | | - u8 *dst = get_rloc_data(dest); |
|---|
| 219 | | - long ret; |
|---|
| 220 | | - |
|---|
| 221 | | - if (!maxlen) |
|---|
| 222 | | - return; |
|---|
| 223 | | - |
|---|
| 224 | | - ret = strlcpy(dst, current->comm, maxlen); |
|---|
| 225 | | - *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest)); |
|---|
| 226 | | -} |
|---|
| 227 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string)); |
|---|
| 228 | | - |
|---|
| 229 | | -void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs, |
|---|
| 230 | | - void *data, void *dest) |
|---|
| 231 | | -{ |
|---|
| 232 | | - *(u32 *)dest = strlen(current->comm) + 1; |
|---|
| 233 | | -} |
|---|
| 234 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size)); |
|---|
| 235 | | - |
|---|
| 236 | | -static const struct fetch_type *find_fetch_type(const char *type, |
|---|
| 237 | | - const struct fetch_type *ftbl) |
|---|
| 101 | +static const struct fetch_type *find_fetch_type(const char *type) |
|---|
| 238 | 102 | { |
|---|
| 239 | 103 | int i; |
|---|
| 240 | 104 | |
|---|
| .. | .. |
|---|
| 255 | 119 | |
|---|
| 256 | 120 | switch (bs) { |
|---|
| 257 | 121 | case 8: |
|---|
| 258 | | - return find_fetch_type("u8", ftbl); |
|---|
| 122 | + return find_fetch_type("u8"); |
|---|
| 259 | 123 | case 16: |
|---|
| 260 | | - return find_fetch_type("u16", ftbl); |
|---|
| 124 | + return find_fetch_type("u16"); |
|---|
| 261 | 125 | case 32: |
|---|
| 262 | | - return find_fetch_type("u32", ftbl); |
|---|
| 126 | + return find_fetch_type("u32"); |
|---|
| 263 | 127 | case 64: |
|---|
| 264 | | - return find_fetch_type("u64", ftbl); |
|---|
| 128 | + return find_fetch_type("u64"); |
|---|
| 265 | 129 | default: |
|---|
| 266 | 130 | goto fail; |
|---|
| 267 | 131 | } |
|---|
| 268 | 132 | } |
|---|
| 269 | 133 | |
|---|
| 270 | | - for (i = 0; ftbl[i].name; i++) { |
|---|
| 271 | | - if (strcmp(type, ftbl[i].name) == 0) |
|---|
| 272 | | - return &ftbl[i]; |
|---|
| 134 | + for (i = 0; probe_fetch_types[i].name; i++) { |
|---|
| 135 | + if (strcmp(type, probe_fetch_types[i].name) == 0) |
|---|
| 136 | + return &probe_fetch_types[i]; |
|---|
| 273 | 137 | } |
|---|
| 274 | 138 | |
|---|
| 275 | 139 | fail: |
|---|
| 276 | 140 | return NULL; |
|---|
| 277 | 141 | } |
|---|
| 278 | 142 | |
|---|
| 279 | | -/* Special function : only accept unsigned long */ |
|---|
| 280 | | -static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
|---|
| 143 | +static struct trace_probe_log trace_probe_log; |
|---|
| 144 | + |
|---|
| 145 | +void trace_probe_log_init(const char *subsystem, int argc, const char **argv) |
|---|
| 281 | 146 | { |
|---|
| 282 | | - *(unsigned long *)dest = kernel_stack_pointer(regs); |
|---|
| 147 | + trace_probe_log.subsystem = subsystem; |
|---|
| 148 | + trace_probe_log.argc = argc; |
|---|
| 149 | + trace_probe_log.argv = argv; |
|---|
| 150 | + trace_probe_log.index = 0; |
|---|
| 283 | 151 | } |
|---|
| 284 | | -NOKPROBE_SYMBOL(fetch_kernel_stack_address); |
|---|
| 285 | 152 | |
|---|
| 286 | | -static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
|---|
| 153 | +void trace_probe_log_clear(void) |
|---|
| 287 | 154 | { |
|---|
| 288 | | - *(unsigned long *)dest = user_stack_pointer(regs); |
|---|
| 155 | + memset(&trace_probe_log, 0, sizeof(trace_probe_log)); |
|---|
| 289 | 156 | } |
|---|
| 290 | | -NOKPROBE_SYMBOL(fetch_user_stack_address); |
|---|
| 291 | 157 | |
|---|
| 292 | | -static fetch_func_t get_fetch_size_function(const struct fetch_type *type, |
|---|
| 293 | | - fetch_func_t orig_fn, |
|---|
| 294 | | - const struct fetch_type *ftbl) |
|---|
| 158 | +void trace_probe_log_set_index(int index) |
|---|
| 295 | 159 | { |
|---|
| 296 | | - int i; |
|---|
| 160 | + trace_probe_log.index = index; |
|---|
| 161 | +} |
|---|
| 297 | 162 | |
|---|
| 298 | | - if (type != &ftbl[FETCH_TYPE_STRING]) |
|---|
| 299 | | - return NULL; /* Only string type needs size function */ |
|---|
| 163 | +void __trace_probe_log_err(int offset, int err_type) |
|---|
| 164 | +{ |
|---|
| 165 | + char *command, *p; |
|---|
| 166 | + int i, len = 0, pos = 0; |
|---|
| 300 | 167 | |
|---|
| 301 | | - for (i = 0; i < FETCH_MTD_END; i++) |
|---|
| 302 | | - if (type->fetch[i] == orig_fn) |
|---|
| 303 | | - return ftbl[FETCH_TYPE_STRSIZE].fetch[i]; |
|---|
| 168 | + if (!trace_probe_log.argv) |
|---|
| 169 | + return; |
|---|
| 304 | 170 | |
|---|
| 305 | | - WARN_ON(1); /* This should not happen */ |
|---|
| 171 | + /* Recalcurate the length and allocate buffer */ |
|---|
| 172 | + for (i = 0; i < trace_probe_log.argc; i++) { |
|---|
| 173 | + if (i == trace_probe_log.index) |
|---|
| 174 | + pos = len; |
|---|
| 175 | + len += strlen(trace_probe_log.argv[i]) + 1; |
|---|
| 176 | + } |
|---|
| 177 | + command = kzalloc(len, GFP_KERNEL); |
|---|
| 178 | + if (!command) |
|---|
| 179 | + return; |
|---|
| 306 | 180 | |
|---|
| 307 | | - return NULL; |
|---|
| 181 | + if (trace_probe_log.index >= trace_probe_log.argc) { |
|---|
| 182 | + /** |
|---|
| 183 | + * Set the error position is next to the last arg + space. |
|---|
| 184 | + * Note that len includes the terminal null and the cursor |
|---|
| 185 | + * appaers at pos + 1. |
|---|
| 186 | + */ |
|---|
| 187 | + pos = len; |
|---|
| 188 | + offset = 0; |
|---|
| 189 | + } |
|---|
| 190 | + |
|---|
| 191 | + /* And make a command string from argv array */ |
|---|
| 192 | + p = command; |
|---|
| 193 | + for (i = 0; i < trace_probe_log.argc; i++) { |
|---|
| 194 | + len = strlen(trace_probe_log.argv[i]); |
|---|
| 195 | + strcpy(p, trace_probe_log.argv[i]); |
|---|
| 196 | + p[len] = ' '; |
|---|
| 197 | + p += len + 1; |
|---|
| 198 | + } |
|---|
| 199 | + *(p - 1) = '\0'; |
|---|
| 200 | + |
|---|
| 201 | + tracing_log_err(NULL, trace_probe_log.subsystem, command, |
|---|
| 202 | + trace_probe_err_text, err_type, pos + offset); |
|---|
| 203 | + |
|---|
| 204 | + kfree(command); |
|---|
| 308 | 205 | } |
|---|
| 309 | 206 | |
|---|
| 310 | 207 | /* Split symbol and offset. */ |
|---|
| .. | .. |
|---|
| 328 | 225 | return 0; |
|---|
| 329 | 226 | } |
|---|
| 330 | 227 | |
|---|
| 228 | +/* @buf must has MAX_EVENT_NAME_LEN size */ |
|---|
| 229 | +int traceprobe_parse_event_name(const char **pevent, const char **pgroup, |
|---|
| 230 | + char *buf, int offset) |
|---|
| 231 | +{ |
|---|
| 232 | + const char *slash, *event = *pevent; |
|---|
| 233 | + int len; |
|---|
| 234 | + |
|---|
| 235 | + slash = strchr(event, '/'); |
|---|
| 236 | + if (slash) { |
|---|
| 237 | + if (slash == event) { |
|---|
| 238 | + trace_probe_log_err(offset, NO_GROUP_NAME); |
|---|
| 239 | + return -EINVAL; |
|---|
| 240 | + } |
|---|
| 241 | + if (slash - event + 1 > MAX_EVENT_NAME_LEN) { |
|---|
| 242 | + trace_probe_log_err(offset, GROUP_TOO_LONG); |
|---|
| 243 | + return -EINVAL; |
|---|
| 244 | + } |
|---|
| 245 | + strlcpy(buf, event, slash - event + 1); |
|---|
| 246 | + if (!is_good_name(buf)) { |
|---|
| 247 | + trace_probe_log_err(offset, BAD_GROUP_NAME); |
|---|
| 248 | + return -EINVAL; |
|---|
| 249 | + } |
|---|
| 250 | + *pgroup = buf; |
|---|
| 251 | + *pevent = slash + 1; |
|---|
| 252 | + offset += slash - event + 1; |
|---|
| 253 | + event = *pevent; |
|---|
| 254 | + } |
|---|
| 255 | + len = strlen(event); |
|---|
| 256 | + if (len == 0) { |
|---|
| 257 | + trace_probe_log_err(offset, NO_EVENT_NAME); |
|---|
| 258 | + return -EINVAL; |
|---|
| 259 | + } else if (len > MAX_EVENT_NAME_LEN) { |
|---|
| 260 | + trace_probe_log_err(offset, EVENT_TOO_LONG); |
|---|
| 261 | + return -EINVAL; |
|---|
| 262 | + } |
|---|
| 263 | + if (!is_good_name(event)) { |
|---|
| 264 | + trace_probe_log_err(offset, BAD_EVENT_NAME); |
|---|
| 265 | + return -EINVAL; |
|---|
| 266 | + } |
|---|
| 267 | + return 0; |
|---|
| 268 | +} |
|---|
| 269 | + |
|---|
| 331 | 270 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) |
|---|
| 332 | 271 | |
|---|
| 333 | 272 | static int parse_probe_vars(char *arg, const struct fetch_type *t, |
|---|
| 334 | | - struct fetch_param *f, bool is_return, |
|---|
| 335 | | - bool is_kprobe) |
|---|
| 273 | + struct fetch_insn *code, unsigned int flags, int offs) |
|---|
| 336 | 274 | { |
|---|
| 337 | | - int ret = 0; |
|---|
| 338 | 275 | unsigned long param; |
|---|
| 276 | + int ret = 0; |
|---|
| 277 | + int len; |
|---|
| 339 | 278 | |
|---|
| 340 | 279 | if (strcmp(arg, "retval") == 0) { |
|---|
| 341 | | - if (is_return) |
|---|
| 342 | | - f->fn = t->fetch[FETCH_MTD_retval]; |
|---|
| 343 | | - else |
|---|
| 280 | + if (flags & TPARG_FL_RETURN) { |
|---|
| 281 | + code->op = FETCH_OP_RETVAL; |
|---|
| 282 | + } else { |
|---|
| 283 | + trace_probe_log_err(offs, RETVAL_ON_PROBE); |
|---|
| 344 | 284 | ret = -EINVAL; |
|---|
| 345 | | - } else if (strncmp(arg, "stack", 5) == 0) { |
|---|
| 346 | | - if (arg[5] == '\0') { |
|---|
| 347 | | - if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR)) |
|---|
| 348 | | - return -EINVAL; |
|---|
| 349 | | - |
|---|
| 350 | | - if (is_kprobe) |
|---|
| 351 | | - f->fn = fetch_kernel_stack_address; |
|---|
| 352 | | - else |
|---|
| 353 | | - f->fn = fetch_user_stack_address; |
|---|
| 354 | | - } else if (isdigit(arg[5])) { |
|---|
| 355 | | - ret = kstrtoul(arg + 5, 10, ¶m); |
|---|
| 356 | | - if (ret || (is_kprobe && param > PARAM_MAX_STACK)) |
|---|
| 285 | + } |
|---|
| 286 | + } else if ((len = str_has_prefix(arg, "stack"))) { |
|---|
| 287 | + if (arg[len] == '\0') { |
|---|
| 288 | + code->op = FETCH_OP_STACKP; |
|---|
| 289 | + } else if (isdigit(arg[len])) { |
|---|
| 290 | + ret = kstrtoul(arg + len, 10, ¶m); |
|---|
| 291 | + if (ret) { |
|---|
| 292 | + goto inval_var; |
|---|
| 293 | + } else if ((flags & TPARG_FL_KERNEL) && |
|---|
| 294 | + param > PARAM_MAX_STACK) { |
|---|
| 295 | + trace_probe_log_err(offs, BAD_STACK_NUM); |
|---|
| 357 | 296 | ret = -EINVAL; |
|---|
| 358 | | - else { |
|---|
| 359 | | - f->fn = t->fetch[FETCH_MTD_stack]; |
|---|
| 360 | | - f->data = (void *)param; |
|---|
| 297 | + } else { |
|---|
| 298 | + code->op = FETCH_OP_STACK; |
|---|
| 299 | + code->param = (unsigned int)param; |
|---|
| 361 | 300 | } |
|---|
| 362 | 301 | } else |
|---|
| 363 | | - ret = -EINVAL; |
|---|
| 364 | | - } else if (strcmp(arg, "comm") == 0) { |
|---|
| 365 | | - if (strcmp(t->name, "string") != 0 && |
|---|
| 366 | | - strcmp(t->name, "string_size") != 0) |
|---|
| 302 | + goto inval_var; |
|---|
| 303 | + } else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { |
|---|
| 304 | + code->op = FETCH_OP_COMM; |
|---|
| 305 | +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
|---|
| 306 | + } else if (((flags & TPARG_FL_MASK) == |
|---|
| 307 | + (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) && |
|---|
| 308 | + (len = str_has_prefix(arg, "arg"))) { |
|---|
| 309 | + ret = kstrtoul(arg + len, 10, ¶m); |
|---|
| 310 | + if (ret) { |
|---|
| 311 | + goto inval_var; |
|---|
| 312 | + } else if (!param || param > PARAM_MAX_STACK) { |
|---|
| 313 | + trace_probe_log_err(offs, BAD_ARG_NUM); |
|---|
| 367 | 314 | return -EINVAL; |
|---|
| 368 | | - f->fn = t->fetch[FETCH_MTD_comm]; |
|---|
| 315 | + } |
|---|
| 316 | + code->op = FETCH_OP_ARG; |
|---|
| 317 | + code->param = (unsigned int)param - 1; |
|---|
| 318 | +#endif |
|---|
| 369 | 319 | } else |
|---|
| 370 | | - ret = -EINVAL; |
|---|
| 320 | + goto inval_var; |
|---|
| 371 | 321 | |
|---|
| 372 | 322 | return ret; |
|---|
| 323 | + |
|---|
| 324 | +inval_var: |
|---|
| 325 | + trace_probe_log_err(offs, BAD_VAR); |
|---|
| 326 | + return -EINVAL; |
|---|
| 327 | +} |
|---|
| 328 | + |
|---|
| 329 | +static int str_to_immediate(char *str, unsigned long *imm) |
|---|
| 330 | +{ |
|---|
| 331 | + if (isdigit(str[0])) |
|---|
| 332 | + return kstrtoul(str, 0, imm); |
|---|
| 333 | + else if (str[0] == '-') |
|---|
| 334 | + return kstrtol(str, 0, (long *)imm); |
|---|
| 335 | + else if (str[0] == '+') |
|---|
| 336 | + return kstrtol(str + 1, 0, (long *)imm); |
|---|
| 337 | + return -EINVAL; |
|---|
| 338 | +} |
|---|
| 339 | + |
|---|
| 340 | +static int __parse_imm_string(char *str, char **pbuf, int offs) |
|---|
| 341 | +{ |
|---|
| 342 | + size_t len = strlen(str); |
|---|
| 343 | + |
|---|
| 344 | + if (str[len - 1] != '"') { |
|---|
| 345 | + trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE); |
|---|
| 346 | + return -EINVAL; |
|---|
| 347 | + } |
|---|
| 348 | + *pbuf = kstrndup(str, len - 1, GFP_KERNEL); |
|---|
| 349 | + return 0; |
|---|
| 373 | 350 | } |
|---|
| 374 | 351 | |
|---|
| 375 | 352 | /* Recursive argument parser */ |
|---|
| 376 | | -static int parse_probe_arg(char *arg, const struct fetch_type *t, |
|---|
| 377 | | - struct fetch_param *f, bool is_return, bool is_kprobe, |
|---|
| 378 | | - const struct fetch_type *ftbl) |
|---|
| 353 | +static int |
|---|
| 354 | +parse_probe_arg(char *arg, const struct fetch_type *type, |
|---|
| 355 | + struct fetch_insn **pcode, struct fetch_insn *end, |
|---|
| 356 | + unsigned int flags, int offs) |
|---|
| 379 | 357 | { |
|---|
| 358 | + struct fetch_insn *code = *pcode; |
|---|
| 380 | 359 | unsigned long param; |
|---|
| 381 | | - long offset; |
|---|
| 360 | + int deref = FETCH_OP_DEREF; |
|---|
| 361 | + long offset = 0; |
|---|
| 382 | 362 | char *tmp; |
|---|
| 383 | 363 | int ret = 0; |
|---|
| 384 | 364 | |
|---|
| 385 | 365 | switch (arg[0]) { |
|---|
| 386 | 366 | case '$': |
|---|
| 387 | | - ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe); |
|---|
| 367 | + ret = parse_probe_vars(arg + 1, type, code, flags, offs); |
|---|
| 388 | 368 | break; |
|---|
| 389 | 369 | |
|---|
| 390 | 370 | case '%': /* named register */ |
|---|
| 391 | 371 | ret = regs_query_register_offset(arg + 1); |
|---|
| 392 | 372 | if (ret >= 0) { |
|---|
| 393 | | - f->fn = t->fetch[FETCH_MTD_reg]; |
|---|
| 394 | | - f->data = (void *)(unsigned long)ret; |
|---|
| 373 | + code->op = FETCH_OP_REG; |
|---|
| 374 | + code->param = (unsigned int)ret; |
|---|
| 395 | 375 | ret = 0; |
|---|
| 396 | | - } |
|---|
| 376 | + } else |
|---|
| 377 | + trace_probe_log_err(offs, BAD_REG_NAME); |
|---|
| 397 | 378 | break; |
|---|
| 398 | 379 | |
|---|
| 399 | 380 | case '@': /* memory, file-offset or symbol */ |
|---|
| 400 | 381 | if (isdigit(arg[1])) { |
|---|
| 401 | 382 | ret = kstrtoul(arg + 1, 0, ¶m); |
|---|
| 402 | | - if (ret) |
|---|
| 383 | + if (ret) { |
|---|
| 384 | + trace_probe_log_err(offs, BAD_MEM_ADDR); |
|---|
| 403 | 385 | break; |
|---|
| 404 | | - |
|---|
| 405 | | - f->fn = t->fetch[FETCH_MTD_memory]; |
|---|
| 406 | | - f->data = (void *)param; |
|---|
| 386 | + } |
|---|
| 387 | + /* load address */ |
|---|
| 388 | + code->op = FETCH_OP_IMM; |
|---|
| 389 | + code->immediate = param; |
|---|
| 407 | 390 | } else if (arg[1] == '+') { |
|---|
| 408 | 391 | /* kprobes don't support file offsets */ |
|---|
| 409 | | - if (is_kprobe) |
|---|
| 392 | + if (flags & TPARG_FL_KERNEL) { |
|---|
| 393 | + trace_probe_log_err(offs, FILE_ON_KPROBE); |
|---|
| 410 | 394 | return -EINVAL; |
|---|
| 411 | | - |
|---|
| 395 | + } |
|---|
| 412 | 396 | ret = kstrtol(arg + 2, 0, &offset); |
|---|
| 413 | | - if (ret) |
|---|
| 397 | + if (ret) { |
|---|
| 398 | + trace_probe_log_err(offs, BAD_FILE_OFFS); |
|---|
| 414 | 399 | break; |
|---|
| 400 | + } |
|---|
| 415 | 401 | |
|---|
| 416 | | - f->fn = t->fetch[FETCH_MTD_file_offset]; |
|---|
| 417 | | - f->data = (void *)offset; |
|---|
| 402 | + code->op = FETCH_OP_FOFFS; |
|---|
| 403 | + code->immediate = (unsigned long)offset; // imm64? |
|---|
| 418 | 404 | } else { |
|---|
| 419 | 405 | /* uprobes don't support symbols */ |
|---|
| 420 | | - if (!is_kprobe) |
|---|
| 406 | + if (!(flags & TPARG_FL_KERNEL)) { |
|---|
| 407 | + trace_probe_log_err(offs, SYM_ON_UPROBE); |
|---|
| 421 | 408 | return -EINVAL; |
|---|
| 422 | | - |
|---|
| 423 | | - ret = traceprobe_split_symbol_offset(arg + 1, &offset); |
|---|
| 424 | | - if (ret) |
|---|
| 425 | | - break; |
|---|
| 426 | | - |
|---|
| 427 | | - f->data = alloc_symbol_cache(arg + 1, offset); |
|---|
| 428 | | - if (f->data) |
|---|
| 429 | | - f->fn = t->fetch[FETCH_MTD_symbol]; |
|---|
| 409 | + } |
|---|
| 410 | + /* Preserve symbol for updating */ |
|---|
| 411 | + code->op = FETCH_NOP_SYMBOL; |
|---|
| 412 | + code->data = kstrdup(arg + 1, GFP_KERNEL); |
|---|
| 413 | + if (!code->data) |
|---|
| 414 | + return -ENOMEM; |
|---|
| 415 | + if (++code == end) { |
|---|
| 416 | + trace_probe_log_err(offs, TOO_MANY_OPS); |
|---|
| 417 | + return -EINVAL; |
|---|
| 418 | + } |
|---|
| 419 | + code->op = FETCH_OP_IMM; |
|---|
| 420 | + code->immediate = 0; |
|---|
| 430 | 421 | } |
|---|
| 422 | + /* These are fetching from memory */ |
|---|
| 423 | + if (++code == end) { |
|---|
| 424 | + trace_probe_log_err(offs, TOO_MANY_OPS); |
|---|
| 425 | + return -EINVAL; |
|---|
| 426 | + } |
|---|
| 427 | + *pcode = code; |
|---|
| 428 | + code->op = FETCH_OP_DEREF; |
|---|
| 429 | + code->offset = offset; |
|---|
| 431 | 430 | break; |
|---|
| 432 | 431 | |
|---|
| 433 | 432 | case '+': /* deref memory */ |
|---|
| 434 | | - arg++; /* Skip '+', because kstrtol() rejects it. */ |
|---|
| 435 | 433 | case '-': |
|---|
| 434 | + if (arg[1] == 'u') { |
|---|
| 435 | + deref = FETCH_OP_UDEREF; |
|---|
| 436 | + arg[1] = arg[0]; |
|---|
| 437 | + arg++; |
|---|
| 438 | + } |
|---|
| 439 | + if (arg[0] == '+') |
|---|
| 440 | + arg++; /* Skip '+', because kstrtol() rejects it. */ |
|---|
| 436 | 441 | tmp = strchr(arg, '('); |
|---|
| 437 | | - if (!tmp) |
|---|
| 438 | | - break; |
|---|
| 439 | | - |
|---|
| 442 | + if (!tmp) { |
|---|
| 443 | + trace_probe_log_err(offs, DEREF_NEED_BRACE); |
|---|
| 444 | + return -EINVAL; |
|---|
| 445 | + } |
|---|
| 440 | 446 | *tmp = '\0'; |
|---|
| 441 | 447 | ret = kstrtol(arg, 0, &offset); |
|---|
| 442 | | - |
|---|
| 443 | | - if (ret) |
|---|
| 448 | + if (ret) { |
|---|
| 449 | + trace_probe_log_err(offs, BAD_DEREF_OFFS); |
|---|
| 444 | 450 | break; |
|---|
| 445 | | - |
|---|
| 451 | + } |
|---|
| 452 | + offs += (tmp + 1 - arg) + (arg[0] != '-' ? 1 : 0); |
|---|
| 446 | 453 | arg = tmp + 1; |
|---|
| 447 | 454 | tmp = strrchr(arg, ')'); |
|---|
| 455 | + if (!tmp) { |
|---|
| 456 | + trace_probe_log_err(offs + strlen(arg), |
|---|
| 457 | + DEREF_OPEN_BRACE); |
|---|
| 458 | + return -EINVAL; |
|---|
| 459 | + } else { |
|---|
| 460 | + const struct fetch_type *t2 = find_fetch_type(NULL); |
|---|
| 448 | 461 | |
|---|
| 449 | | - if (tmp) { |
|---|
| 450 | | - struct deref_fetch_param *dprm; |
|---|
| 451 | | - const struct fetch_type *t2; |
|---|
| 452 | | - |
|---|
| 453 | | - t2 = find_fetch_type(NULL, ftbl); |
|---|
| 454 | 462 | *tmp = '\0'; |
|---|
| 455 | | - dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL); |
|---|
| 456 | | - |
|---|
| 457 | | - if (!dprm) |
|---|
| 458 | | - return -ENOMEM; |
|---|
| 459 | | - |
|---|
| 460 | | - dprm->offset = offset; |
|---|
| 461 | | - dprm->fetch = t->fetch[FETCH_MTD_memory]; |
|---|
| 462 | | - dprm->fetch_size = get_fetch_size_function(t, |
|---|
| 463 | | - dprm->fetch, ftbl); |
|---|
| 464 | | - ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, |
|---|
| 465 | | - is_kprobe, ftbl); |
|---|
| 463 | + ret = parse_probe_arg(arg, t2, &code, end, flags, offs); |
|---|
| 466 | 464 | if (ret) |
|---|
| 467 | | - kfree(dprm); |
|---|
| 468 | | - else { |
|---|
| 469 | | - f->fn = t->fetch[FETCH_MTD_deref]; |
|---|
| 470 | | - f->data = (void *)dprm; |
|---|
| 465 | + break; |
|---|
| 466 | + if (code->op == FETCH_OP_COMM || |
|---|
| 467 | + code->op == FETCH_OP_DATA) { |
|---|
| 468 | + trace_probe_log_err(offs, COMM_CANT_DEREF); |
|---|
| 469 | + return -EINVAL; |
|---|
| 471 | 470 | } |
|---|
| 471 | + if (++code == end) { |
|---|
| 472 | + trace_probe_log_err(offs, TOO_MANY_OPS); |
|---|
| 473 | + return -EINVAL; |
|---|
| 474 | + } |
|---|
| 475 | + *pcode = code; |
|---|
| 476 | + |
|---|
| 477 | + code->op = deref; |
|---|
| 478 | + code->offset = offset; |
|---|
| 479 | + } |
|---|
| 480 | + break; |
|---|
| 481 | + case '\\': /* Immediate value */ |
|---|
| 482 | + if (arg[1] == '"') { /* Immediate string */ |
|---|
| 483 | + ret = __parse_imm_string(arg + 2, &tmp, offs + 2); |
|---|
| 484 | + if (ret) |
|---|
| 485 | + break; |
|---|
| 486 | + code->op = FETCH_OP_DATA; |
|---|
| 487 | + code->data = tmp; |
|---|
| 488 | + } else { |
|---|
| 489 | + ret = str_to_immediate(arg + 1, &code->immediate); |
|---|
| 490 | + if (ret) |
|---|
| 491 | + trace_probe_log_err(offs + 1, BAD_IMM); |
|---|
| 492 | + else |
|---|
| 493 | + code->op = FETCH_OP_IMM; |
|---|
| 472 | 494 | } |
|---|
| 473 | 495 | break; |
|---|
| 474 | 496 | } |
|---|
| 475 | | - if (!ret && !f->fn) { /* Parsed, but do not find fetch method */ |
|---|
| 476 | | - pr_info("%s type has no corresponding fetch method.\n", t->name); |
|---|
| 497 | + if (!ret && code->op == FETCH_OP_NOP) { |
|---|
| 498 | + /* Parsed, but do not find fetch method */ |
|---|
| 499 | + trace_probe_log_err(offs, BAD_FETCH_ARG); |
|---|
| 477 | 500 | ret = -EINVAL; |
|---|
| 478 | 501 | } |
|---|
| 479 | | - |
|---|
| 480 | 502 | return ret; |
|---|
| 481 | 503 | } |
|---|
| 482 | 504 | |
|---|
| .. | .. |
|---|
| 485 | 507 | /* Bitfield type needs to be parsed into a fetch function */ |
|---|
| 486 | 508 | static int __parse_bitfield_probe_arg(const char *bf, |
|---|
| 487 | 509 | const struct fetch_type *t, |
|---|
| 488 | | - struct fetch_param *f) |
|---|
| 510 | + struct fetch_insn **pcode) |
|---|
| 489 | 511 | { |
|---|
| 490 | | - struct bitfield_fetch_param *bprm; |
|---|
| 512 | + struct fetch_insn *code = *pcode; |
|---|
| 491 | 513 | unsigned long bw, bo; |
|---|
| 492 | 514 | char *tail; |
|---|
| 493 | 515 | |
|---|
| 494 | 516 | if (*bf != 'b') |
|---|
| 495 | 517 | return 0; |
|---|
| 496 | 518 | |
|---|
| 497 | | - bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); |
|---|
| 498 | | - if (!bprm) |
|---|
| 499 | | - return -ENOMEM; |
|---|
| 500 | | - |
|---|
| 501 | | - bprm->orig = *f; |
|---|
| 502 | | - f->fn = t->fetch[FETCH_MTD_bitfield]; |
|---|
| 503 | | - f->data = (void *)bprm; |
|---|
| 504 | 519 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ |
|---|
| 505 | 520 | |
|---|
| 506 | 521 | if (bw == 0 || *tail != '@') |
|---|
| .. | .. |
|---|
| 511 | 526 | |
|---|
| 512 | 527 | if (tail == bf || *tail != '/') |
|---|
| 513 | 528 | return -EINVAL; |
|---|
| 529 | + code++; |
|---|
| 530 | + if (code->op != FETCH_OP_NOP) |
|---|
| 531 | + return -EINVAL; |
|---|
| 532 | + *pcode = code; |
|---|
| 514 | 533 | |
|---|
| 515 | | - bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); |
|---|
| 516 | | - bprm->low_shift = bprm->hi_shift + bo; |
|---|
| 534 | + code->op = FETCH_OP_MOD_BF; |
|---|
| 535 | + code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); |
|---|
| 536 | + code->rshift = BYTES_TO_BITS(t->size) - bw; |
|---|
| 537 | + code->basesize = t->size; |
|---|
| 517 | 538 | |
|---|
| 518 | 539 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; |
|---|
| 519 | 540 | } |
|---|
| 520 | 541 | |
|---|
| 521 | 542 | /* String length checking wrapper */ |
|---|
| 522 | | -int traceprobe_parse_probe_arg(char *arg, ssize_t *size, |
|---|
| 523 | | - struct probe_arg *parg, bool is_return, bool is_kprobe, |
|---|
| 524 | | - const struct fetch_type *ftbl) |
|---|
| 543 | +static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, |
|---|
| 544 | + struct probe_arg *parg, unsigned int flags, int offset) |
|---|
| 525 | 545 | { |
|---|
| 526 | | - const char *t; |
|---|
| 527 | | - int ret; |
|---|
| 546 | + struct fetch_insn *code, *scode, *tmp = NULL; |
|---|
| 547 | + char *t, *t2, *t3; |
|---|
| 548 | + int ret, len; |
|---|
| 528 | 549 | |
|---|
| 529 | | - if (strlen(arg) > MAX_ARGSTR_LEN) { |
|---|
| 530 | | - pr_info("Argument is too long.: %s\n", arg); |
|---|
| 531 | | - return -ENOSPC; |
|---|
| 550 | + len = strlen(arg); |
|---|
| 551 | + if (len > MAX_ARGSTR_LEN) { |
|---|
| 552 | + trace_probe_log_err(offset, ARG_TOO_LONG); |
|---|
| 553 | + return -EINVAL; |
|---|
| 554 | + } else if (len == 0) { |
|---|
| 555 | + trace_probe_log_err(offset, NO_ARG_BODY); |
|---|
| 556 | + return -EINVAL; |
|---|
| 532 | 557 | } |
|---|
| 558 | + |
|---|
| 533 | 559 | parg->comm = kstrdup(arg, GFP_KERNEL); |
|---|
| 534 | | - if (!parg->comm) { |
|---|
| 535 | | - pr_info("Failed to allocate memory for command '%s'.\n", arg); |
|---|
| 560 | + if (!parg->comm) |
|---|
| 536 | 561 | return -ENOMEM; |
|---|
| 537 | | - } |
|---|
| 538 | | - t = strchr(parg->comm, ':'); |
|---|
| 562 | + |
|---|
| 563 | + t = strchr(arg, ':'); |
|---|
| 539 | 564 | if (t) { |
|---|
| 540 | | - arg[t - parg->comm] = '\0'; |
|---|
| 541 | | - t++; |
|---|
| 565 | + *t = '\0'; |
|---|
| 566 | + t2 = strchr(++t, '['); |
|---|
| 567 | + if (t2) { |
|---|
| 568 | + *t2++ = '\0'; |
|---|
| 569 | + t3 = strchr(t2, ']'); |
|---|
| 570 | + if (!t3) { |
|---|
| 571 | + offset += t2 + strlen(t2) - arg; |
|---|
| 572 | + trace_probe_log_err(offset, |
|---|
| 573 | + ARRAY_NO_CLOSE); |
|---|
| 574 | + return -EINVAL; |
|---|
| 575 | + } else if (t3[1] != '\0') { |
|---|
| 576 | + trace_probe_log_err(offset + t3 + 1 - arg, |
|---|
| 577 | + BAD_ARRAY_SUFFIX); |
|---|
| 578 | + return -EINVAL; |
|---|
| 579 | + } |
|---|
| 580 | + *t3 = '\0'; |
|---|
| 581 | + if (kstrtouint(t2, 0, &parg->count) || !parg->count) { |
|---|
| 582 | + trace_probe_log_err(offset + t2 - arg, |
|---|
| 583 | + BAD_ARRAY_NUM); |
|---|
| 584 | + return -EINVAL; |
|---|
| 585 | + } |
|---|
| 586 | + if (parg->count > MAX_ARRAY_LEN) { |
|---|
| 587 | + trace_probe_log_err(offset + t2 - arg, |
|---|
| 588 | + ARRAY_TOO_BIG); |
|---|
| 589 | + return -EINVAL; |
|---|
| 590 | + } |
|---|
| 591 | + } |
|---|
| 542 | 592 | } |
|---|
| 593 | + |
|---|
| 543 | 594 | /* |
|---|
| 544 | | - * The default type of $comm should be "string", and it can't be |
|---|
| 545 | | - * dereferenced. |
|---|
| 595 | + * Since $comm and immediate string can not be dereferred, |
|---|
| 596 | + * we can find those by strcmp. |
|---|
| 546 | 597 | */ |
|---|
| 547 | | - if (!t && strcmp(arg, "$comm") == 0) |
|---|
| 548 | | - t = "string"; |
|---|
| 549 | | - parg->type = find_fetch_type(t, ftbl); |
|---|
| 598 | + if (strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 || |
|---|
| 599 | + strncmp(arg, "\\\"", 2) == 0) { |
|---|
| 600 | + /* The type of $comm must be "string", and not an array. */ |
|---|
| 601 | + if (parg->count || (t && strcmp(t, "string"))) |
|---|
| 602 | + return -EINVAL; |
|---|
| 603 | + parg->type = find_fetch_type("string"); |
|---|
| 604 | + } else |
|---|
| 605 | + parg->type = find_fetch_type(t); |
|---|
| 550 | 606 | if (!parg->type) { |
|---|
| 551 | | - pr_info("Unsupported type: %s\n", t); |
|---|
| 607 | + trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE); |
|---|
| 552 | 608 | return -EINVAL; |
|---|
| 553 | 609 | } |
|---|
| 554 | 610 | parg->offset = *size; |
|---|
| 555 | | - *size += parg->type->size; |
|---|
| 556 | | - ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, |
|---|
| 557 | | - is_kprobe, ftbl); |
|---|
| 611 | + *size += parg->type->size * (parg->count ?: 1); |
|---|
| 558 | 612 | |
|---|
| 559 | | - if (ret >= 0 && t != NULL) |
|---|
| 560 | | - ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); |
|---|
| 561 | | - |
|---|
| 562 | | - if (ret >= 0) { |
|---|
| 563 | | - parg->fetch_size.fn = get_fetch_size_function(parg->type, |
|---|
| 564 | | - parg->fetch.fn, |
|---|
| 565 | | - ftbl); |
|---|
| 566 | | - parg->fetch_size.data = parg->fetch.data; |
|---|
| 613 | + if (parg->count) { |
|---|
| 614 | + len = strlen(parg->type->fmttype) + 6; |
|---|
| 615 | + parg->fmt = kmalloc(len, GFP_KERNEL); |
|---|
| 616 | + if (!parg->fmt) |
|---|
| 617 | + return -ENOMEM; |
|---|
| 618 | + snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, |
|---|
| 619 | + parg->count); |
|---|
| 567 | 620 | } |
|---|
| 621 | + |
|---|
| 622 | + code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL); |
|---|
| 623 | + if (!code) |
|---|
| 624 | + return -ENOMEM; |
|---|
| 625 | + code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; |
|---|
| 626 | + |
|---|
| 627 | + ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], |
|---|
| 628 | + flags, offset); |
|---|
| 629 | + if (ret) |
|---|
| 630 | + goto fail; |
|---|
| 631 | + |
|---|
| 632 | + /* Store operation */ |
|---|
| 633 | + if (!strcmp(parg->type->name, "string") || |
|---|
| 634 | + !strcmp(parg->type->name, "ustring")) { |
|---|
| 635 | + if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF && |
|---|
| 636 | + code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM && |
|---|
| 637 | + code->op != FETCH_OP_DATA) { |
|---|
| 638 | + trace_probe_log_err(offset + (t ? (t - arg) : 0), |
|---|
| 639 | + BAD_STRING); |
|---|
| 640 | + ret = -EINVAL; |
|---|
| 641 | + goto fail; |
|---|
| 642 | + } |
|---|
| 643 | + if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM || |
|---|
| 644 | + code->op == FETCH_OP_DATA) || parg->count) { |
|---|
| 645 | + /* |
|---|
| 646 | + * IMM, DATA and COMM is pointing actual address, those |
|---|
| 647 | + * must be kept, and if parg->count != 0, this is an |
|---|
| 648 | + * array of string pointers instead of string address |
|---|
| 649 | + * itself. |
|---|
| 650 | + */ |
|---|
| 651 | + code++; |
|---|
| 652 | + if (code->op != FETCH_OP_NOP) { |
|---|
| 653 | + trace_probe_log_err(offset, TOO_MANY_OPS); |
|---|
| 654 | + ret = -EINVAL; |
|---|
| 655 | + goto fail; |
|---|
| 656 | + } |
|---|
| 657 | + } |
|---|
| 658 | + /* If op == DEREF, replace it with STRING */ |
|---|
| 659 | + if (!strcmp(parg->type->name, "ustring") || |
|---|
| 660 | + code->op == FETCH_OP_UDEREF) |
|---|
| 661 | + code->op = FETCH_OP_ST_USTRING; |
|---|
| 662 | + else |
|---|
| 663 | + code->op = FETCH_OP_ST_STRING; |
|---|
| 664 | + code->size = parg->type->size; |
|---|
| 665 | + parg->dynamic = true; |
|---|
| 666 | + } else if (code->op == FETCH_OP_DEREF) { |
|---|
| 667 | + code->op = FETCH_OP_ST_MEM; |
|---|
| 668 | + code->size = parg->type->size; |
|---|
| 669 | + } else if (code->op == FETCH_OP_UDEREF) { |
|---|
| 670 | + code->op = FETCH_OP_ST_UMEM; |
|---|
| 671 | + code->size = parg->type->size; |
|---|
| 672 | + } else { |
|---|
| 673 | + code++; |
|---|
| 674 | + if (code->op != FETCH_OP_NOP) { |
|---|
| 675 | + trace_probe_log_err(offset, TOO_MANY_OPS); |
|---|
| 676 | + ret = -EINVAL; |
|---|
| 677 | + goto fail; |
|---|
| 678 | + } |
|---|
| 679 | + code->op = FETCH_OP_ST_RAW; |
|---|
| 680 | + code->size = parg->type->size; |
|---|
| 681 | + } |
|---|
| 682 | + scode = code; |
|---|
| 683 | + /* Modify operation */ |
|---|
| 684 | + if (t != NULL) { |
|---|
| 685 | + ret = __parse_bitfield_probe_arg(t, parg->type, &code); |
|---|
| 686 | + if (ret) { |
|---|
| 687 | + trace_probe_log_err(offset + t - arg, BAD_BITFIELD); |
|---|
| 688 | + goto fail; |
|---|
| 689 | + } |
|---|
| 690 | + } |
|---|
| 691 | + /* Loop(Array) operation */ |
|---|
| 692 | + if (parg->count) { |
|---|
| 693 | + if (scode->op != FETCH_OP_ST_MEM && |
|---|
| 694 | + scode->op != FETCH_OP_ST_STRING && |
|---|
| 695 | + scode->op != FETCH_OP_ST_USTRING) { |
|---|
| 696 | + trace_probe_log_err(offset + (t ? (t - arg) : 0), |
|---|
| 697 | + BAD_STRING); |
|---|
| 698 | + ret = -EINVAL; |
|---|
| 699 | + goto fail; |
|---|
| 700 | + } |
|---|
| 701 | + code++; |
|---|
| 702 | + if (code->op != FETCH_OP_NOP) { |
|---|
| 703 | + trace_probe_log_err(offset, TOO_MANY_OPS); |
|---|
| 704 | + ret = -EINVAL; |
|---|
| 705 | + goto fail; |
|---|
| 706 | + } |
|---|
| 707 | + code->op = FETCH_OP_LP_ARRAY; |
|---|
| 708 | + code->param = parg->count; |
|---|
| 709 | + } |
|---|
| 710 | + code++; |
|---|
| 711 | + code->op = FETCH_OP_END; |
|---|
| 712 | + |
|---|
| 713 | + /* Shrink down the code buffer */ |
|---|
| 714 | + parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL); |
|---|
| 715 | + if (!parg->code) |
|---|
| 716 | + ret = -ENOMEM; |
|---|
| 717 | + else |
|---|
| 718 | + memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); |
|---|
| 719 | + |
|---|
| 720 | +fail: |
|---|
| 721 | + if (ret) { |
|---|
| 722 | + for (code = tmp; code < tmp + FETCH_INSN_MAX; code++) |
|---|
| 723 | + if (code->op == FETCH_NOP_SYMBOL || |
|---|
| 724 | + code->op == FETCH_OP_DATA) |
|---|
| 725 | + kfree(code->data); |
|---|
| 726 | + } |
|---|
| 727 | + kfree(tmp); |
|---|
| 568 | 728 | |
|---|
| 569 | 729 | return ret; |
|---|
| 570 | 730 | } |
|---|
| 571 | 731 | |
|---|
| 572 | 732 | /* Return 1 if name is reserved or already used by another argument */ |
|---|
| 573 | | -int traceprobe_conflict_field_name(const char *name, |
|---|
| 574 | | - struct probe_arg *args, int narg) |
|---|
| 733 | +static int traceprobe_conflict_field_name(const char *name, |
|---|
| 734 | + struct probe_arg *args, int narg) |
|---|
| 575 | 735 | { |
|---|
| 576 | 736 | int i; |
|---|
| 577 | 737 | |
|---|
| .. | .. |
|---|
| 586 | 746 | return 0; |
|---|
| 587 | 747 | } |
|---|
| 588 | 748 | |
|---|
| 589 | | -void traceprobe_update_arg(struct probe_arg *arg) |
|---|
| 749 | +int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg, |
|---|
| 750 | + unsigned int flags) |
|---|
| 590 | 751 | { |
|---|
| 591 | | - if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) |
|---|
| 592 | | - update_bitfield_fetch_param(arg->fetch.data); |
|---|
| 593 | | - else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) |
|---|
| 594 | | - update_deref_fetch_param(arg->fetch.data); |
|---|
| 595 | | - else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) |
|---|
| 596 | | - update_symbol_cache(arg->fetch.data); |
|---|
| 752 | + struct probe_arg *parg = &tp->args[i]; |
|---|
| 753 | + char *body; |
|---|
| 754 | + |
|---|
| 755 | + /* Increment count for freeing args in error case */ |
|---|
| 756 | + tp->nr_args++; |
|---|
| 757 | + |
|---|
| 758 | + body = strchr(arg, '='); |
|---|
| 759 | + if (body) { |
|---|
| 760 | + if (body - arg > MAX_ARG_NAME_LEN) { |
|---|
| 761 | + trace_probe_log_err(0, ARG_NAME_TOO_LONG); |
|---|
| 762 | + return -EINVAL; |
|---|
| 763 | + } else if (body == arg) { |
|---|
| 764 | + trace_probe_log_err(0, NO_ARG_NAME); |
|---|
| 765 | + return -EINVAL; |
|---|
| 766 | + } |
|---|
| 767 | + parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL); |
|---|
| 768 | + body++; |
|---|
| 769 | + } else { |
|---|
| 770 | + /* If argument name is omitted, set "argN" */ |
|---|
| 771 | + parg->name = kasprintf(GFP_KERNEL, "arg%d", i + 1); |
|---|
| 772 | + body = arg; |
|---|
| 773 | + } |
|---|
| 774 | + if (!parg->name) |
|---|
| 775 | + return -ENOMEM; |
|---|
| 776 | + |
|---|
| 777 | + if (!is_good_name(parg->name)) { |
|---|
| 778 | + trace_probe_log_err(0, BAD_ARG_NAME); |
|---|
| 779 | + return -EINVAL; |
|---|
| 780 | + } |
|---|
| 781 | + if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { |
|---|
| 782 | + trace_probe_log_err(0, USED_ARG_NAME); |
|---|
| 783 | + return -EINVAL; |
|---|
| 784 | + } |
|---|
| 785 | + /* Parse fetch argument */ |
|---|
| 786 | + return traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags, |
|---|
| 787 | + body - arg); |
|---|
| 597 | 788 | } |
|---|
| 598 | 789 | |
|---|
| 599 | 790 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
|---|
| 600 | 791 | { |
|---|
| 601 | | - if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) |
|---|
| 602 | | - free_bitfield_fetch_param(arg->fetch.data); |
|---|
| 603 | | - else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) |
|---|
| 604 | | - free_deref_fetch_param(arg->fetch.data); |
|---|
| 605 | | - else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) |
|---|
| 606 | | - free_symbol_cache(arg->fetch.data); |
|---|
| 792 | + struct fetch_insn *code = arg->code; |
|---|
| 607 | 793 | |
|---|
| 794 | + while (code && code->op != FETCH_OP_END) { |
|---|
| 795 | + if (code->op == FETCH_NOP_SYMBOL || |
|---|
| 796 | + code->op == FETCH_OP_DATA) |
|---|
| 797 | + kfree(code->data); |
|---|
| 798 | + code++; |
|---|
| 799 | + } |
|---|
| 800 | + kfree(arg->code); |
|---|
| 608 | 801 | kfree(arg->name); |
|---|
| 609 | 802 | kfree(arg->comm); |
|---|
| 803 | + kfree(arg->fmt); |
|---|
| 610 | 804 | } |
|---|
| 611 | 805 | |
|---|
| 806 | +int traceprobe_update_arg(struct probe_arg *arg) |
|---|
| 807 | +{ |
|---|
| 808 | + struct fetch_insn *code = arg->code; |
|---|
| 809 | + long offset; |
|---|
| 810 | + char *tmp; |
|---|
| 811 | + char c; |
|---|
| 812 | + int ret = 0; |
|---|
| 813 | + |
|---|
| 814 | + while (code && code->op != FETCH_OP_END) { |
|---|
| 815 | + if (code->op == FETCH_NOP_SYMBOL) { |
|---|
| 816 | + if (code[1].op != FETCH_OP_IMM) |
|---|
| 817 | + return -EINVAL; |
|---|
| 818 | + |
|---|
| 819 | + tmp = strpbrk(code->data, "+-"); |
|---|
| 820 | + if (tmp) |
|---|
| 821 | + c = *tmp; |
|---|
| 822 | + ret = traceprobe_split_symbol_offset(code->data, |
|---|
| 823 | + &offset); |
|---|
| 824 | + if (ret) |
|---|
| 825 | + return ret; |
|---|
| 826 | + |
|---|
| 827 | + code[1].immediate = |
|---|
| 828 | + (unsigned long)kallsyms_lookup_name(code->data); |
|---|
| 829 | + if (tmp) |
|---|
| 830 | + *tmp = c; |
|---|
| 831 | + if (!code[1].immediate) |
|---|
| 832 | + return -ENOENT; |
|---|
| 833 | + code[1].immediate += offset; |
|---|
| 834 | + } |
|---|
| 835 | + code++; |
|---|
| 836 | + } |
|---|
| 837 | + return 0; |
|---|
| 838 | +} |
|---|
| 839 | + |
|---|
| 840 | +/* When len=0, we just calculate the needed length */ |
|---|
| 841 | +#define LEN_OR_ZERO (len ? len - pos : 0) |
|---|
| 612 | 842 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
|---|
| 613 | 843 | bool is_return) |
|---|
| 614 | 844 | { |
|---|
| 615 | | - int i; |
|---|
| 845 | + struct probe_arg *parg; |
|---|
| 846 | + int i, j; |
|---|
| 616 | 847 | int pos = 0; |
|---|
| 617 | | - |
|---|
| 618 | 848 | const char *fmt, *arg; |
|---|
| 619 | 849 | |
|---|
| 620 | 850 | if (!is_return) { |
|---|
| .. | .. |
|---|
| 625 | 855 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; |
|---|
| 626 | 856 | } |
|---|
| 627 | 857 | |
|---|
| 628 | | - /* When len=0, we just calculate the needed length */ |
|---|
| 629 | | -#define LEN_OR_ZERO (len ? len - pos : 0) |
|---|
| 630 | | - |
|---|
| 631 | 858 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
|---|
| 632 | 859 | |
|---|
| 633 | 860 | for (i = 0; i < tp->nr_args; i++) { |
|---|
| 634 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", |
|---|
| 635 | | - tp->args[i].name, tp->args[i].type->fmt); |
|---|
| 861 | + parg = tp->args + i; |
|---|
| 862 | + pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name); |
|---|
| 863 | + if (parg->count) { |
|---|
| 864 | + pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s", |
|---|
| 865 | + parg->type->fmt); |
|---|
| 866 | + for (j = 1; j < parg->count; j++) |
|---|
| 867 | + pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s", |
|---|
| 868 | + parg->type->fmt); |
|---|
| 869 | + pos += snprintf(buf + pos, LEN_OR_ZERO, "}"); |
|---|
| 870 | + } else |
|---|
| 871 | + pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", |
|---|
| 872 | + parg->type->fmt); |
|---|
| 636 | 873 | } |
|---|
| 637 | 874 | |
|---|
| 638 | 875 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); |
|---|
| 639 | 876 | |
|---|
| 640 | 877 | for (i = 0; i < tp->nr_args; i++) { |
|---|
| 641 | | - if (strcmp(tp->args[i].type->name, "string") == 0) |
|---|
| 878 | + parg = tp->args + i; |
|---|
| 879 | + if (parg->count) { |
|---|
| 880 | + if ((strcmp(parg->type->name, "string") == 0) || |
|---|
| 881 | + (strcmp(parg->type->name, "ustring") == 0)) |
|---|
| 882 | + fmt = ", __get_str(%s[%d])"; |
|---|
| 883 | + else |
|---|
| 884 | + fmt = ", REC->%s[%d]"; |
|---|
| 885 | + for (j = 0; j < parg->count; j++) |
|---|
| 886 | + pos += snprintf(buf + pos, LEN_OR_ZERO, |
|---|
| 887 | + fmt, parg->name, j); |
|---|
| 888 | + } else { |
|---|
| 889 | + if ((strcmp(parg->type->name, "string") == 0) || |
|---|
| 890 | + (strcmp(parg->type->name, "ustring") == 0)) |
|---|
| 891 | + fmt = ", __get_str(%s)"; |
|---|
| 892 | + else |
|---|
| 893 | + fmt = ", REC->%s"; |
|---|
| 642 | 894 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
|---|
| 643 | | - ", __get_str(%s)", |
|---|
| 644 | | - tp->args[i].name); |
|---|
| 645 | | - else |
|---|
| 646 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", |
|---|
| 647 | | - tp->args[i].name); |
|---|
| 895 | + fmt, parg->name); |
|---|
| 896 | + } |
|---|
| 648 | 897 | } |
|---|
| 649 | | - |
|---|
| 650 | | -#undef LEN_OR_ZERO |
|---|
| 651 | 898 | |
|---|
| 652 | 899 | /* return the length of print_fmt */ |
|---|
| 653 | 900 | return pos; |
|---|
| 654 | 901 | } |
|---|
| 902 | +#undef LEN_OR_ZERO |
|---|
| 655 | 903 | |
|---|
| 656 | | -int set_print_fmt(struct trace_probe *tp, bool is_return) |
|---|
| 904 | +int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return) |
|---|
| 657 | 905 | { |
|---|
| 906 | + struct trace_event_call *call = trace_probe_event_call(tp); |
|---|
| 658 | 907 | int len; |
|---|
| 659 | 908 | char *print_fmt; |
|---|
| 660 | 909 | |
|---|
| .. | .. |
|---|
| 666 | 915 | |
|---|
| 667 | 916 | /* Second: actually write the @print_fmt */ |
|---|
| 668 | 917 | __set_print_fmt(tp, print_fmt, len + 1, is_return); |
|---|
| 669 | | - tp->call.print_fmt = print_fmt; |
|---|
| 918 | + call->print_fmt = print_fmt; |
|---|
| 670 | 919 | |
|---|
| 671 | 920 | return 0; |
|---|
| 672 | 921 | } |
|---|
| 922 | + |
|---|
| 923 | +int traceprobe_define_arg_fields(struct trace_event_call *event_call, |
|---|
| 924 | + size_t offset, struct trace_probe *tp) |
|---|
| 925 | +{ |
|---|
| 926 | + int ret, i; |
|---|
| 927 | + |
|---|
| 928 | + /* Set argument names as fields */ |
|---|
| 929 | + for (i = 0; i < tp->nr_args; i++) { |
|---|
| 930 | + struct probe_arg *parg = &tp->args[i]; |
|---|
| 931 | + const char *fmt = parg->type->fmttype; |
|---|
| 932 | + int size = parg->type->size; |
|---|
| 933 | + |
|---|
| 934 | + if (parg->fmt) |
|---|
| 935 | + fmt = parg->fmt; |
|---|
| 936 | + if (parg->count) |
|---|
| 937 | + size *= parg->count; |
|---|
| 938 | + ret = trace_define_field(event_call, fmt, parg->name, |
|---|
| 939 | + offset + parg->offset, size, |
|---|
| 940 | + parg->type->is_signed, |
|---|
| 941 | + FILTER_OTHER); |
|---|
| 942 | + if (ret) |
|---|
| 943 | + return ret; |
|---|
| 944 | + } |
|---|
| 945 | + return 0; |
|---|
| 946 | +} |
|---|
| 947 | + |
|---|
| 948 | +static void trace_probe_event_free(struct trace_probe_event *tpe) |
|---|
| 949 | +{ |
|---|
| 950 | + kfree(tpe->class.system); |
|---|
| 951 | + kfree(tpe->call.name); |
|---|
| 952 | + kfree(tpe->call.print_fmt); |
|---|
| 953 | + kfree(tpe); |
|---|
| 954 | +} |
|---|
| 955 | + |
|---|
| 956 | +int trace_probe_append(struct trace_probe *tp, struct trace_probe *to) |
|---|
| 957 | +{ |
|---|
| 958 | + if (trace_probe_has_sibling(tp)) |
|---|
| 959 | + return -EBUSY; |
|---|
| 960 | + |
|---|
| 961 | + list_del_init(&tp->list); |
|---|
| 962 | + trace_probe_event_free(tp->event); |
|---|
| 963 | + |
|---|
| 964 | + tp->event = to->event; |
|---|
| 965 | + list_add_tail(&tp->list, trace_probe_probe_list(to)); |
|---|
| 966 | + |
|---|
| 967 | + return 0; |
|---|
| 968 | +} |
|---|
| 969 | + |
|---|
| 970 | +void trace_probe_unlink(struct trace_probe *tp) |
|---|
| 971 | +{ |
|---|
| 972 | + list_del_init(&tp->list); |
|---|
| 973 | + if (list_empty(trace_probe_probe_list(tp))) |
|---|
| 974 | + trace_probe_event_free(tp->event); |
|---|
| 975 | + tp->event = NULL; |
|---|
| 976 | +} |
|---|
| 977 | + |
|---|
| 978 | +void trace_probe_cleanup(struct trace_probe *tp) |
|---|
| 979 | +{ |
|---|
| 980 | + int i; |
|---|
| 981 | + |
|---|
| 982 | + for (i = 0; i < tp->nr_args; i++) |
|---|
| 983 | + traceprobe_free_probe_arg(&tp->args[i]); |
|---|
| 984 | + |
|---|
| 985 | + if (tp->event) |
|---|
| 986 | + trace_probe_unlink(tp); |
|---|
| 987 | +} |
|---|
| 988 | + |
|---|
| 989 | +int trace_probe_init(struct trace_probe *tp, const char *event, |
|---|
| 990 | + const char *group, bool alloc_filter) |
|---|
| 991 | +{ |
|---|
| 992 | + struct trace_event_call *call; |
|---|
| 993 | + size_t size = sizeof(struct trace_probe_event); |
|---|
| 994 | + int ret = 0; |
|---|
| 995 | + |
|---|
| 996 | + if (!event || !group) |
|---|
| 997 | + return -EINVAL; |
|---|
| 998 | + |
|---|
| 999 | + if (alloc_filter) |
|---|
| 1000 | + size += sizeof(struct trace_uprobe_filter); |
|---|
| 1001 | + |
|---|
| 1002 | + tp->event = kzalloc(size, GFP_KERNEL); |
|---|
| 1003 | + if (!tp->event) |
|---|
| 1004 | + return -ENOMEM; |
|---|
| 1005 | + |
|---|
| 1006 | + INIT_LIST_HEAD(&tp->event->files); |
|---|
| 1007 | + INIT_LIST_HEAD(&tp->event->class.fields); |
|---|
| 1008 | + INIT_LIST_HEAD(&tp->event->probes); |
|---|
| 1009 | + INIT_LIST_HEAD(&tp->list); |
|---|
| 1010 | + list_add(&tp->list, &tp->event->probes); |
|---|
| 1011 | + |
|---|
| 1012 | + call = trace_probe_event_call(tp); |
|---|
| 1013 | + call->class = &tp->event->class; |
|---|
| 1014 | + call->name = kstrdup(event, GFP_KERNEL); |
|---|
| 1015 | + if (!call->name) { |
|---|
| 1016 | + ret = -ENOMEM; |
|---|
| 1017 | + goto error; |
|---|
| 1018 | + } |
|---|
| 1019 | + |
|---|
| 1020 | + tp->event->class.system = kstrdup(group, GFP_KERNEL); |
|---|
| 1021 | + if (!tp->event->class.system) { |
|---|
| 1022 | + ret = -ENOMEM; |
|---|
| 1023 | + goto error; |
|---|
| 1024 | + } |
|---|
| 1025 | + |
|---|
| 1026 | + return 0; |
|---|
| 1027 | + |
|---|
| 1028 | +error: |
|---|
| 1029 | + trace_probe_cleanup(tp); |
|---|
| 1030 | + return ret; |
|---|
| 1031 | +} |
|---|
| 1032 | + |
|---|
| 1033 | +static struct trace_event_call * |
|---|
| 1034 | +find_trace_event_call(const char *system, const char *event_name) |
|---|
| 1035 | +{ |
|---|
| 1036 | + struct trace_event_call *tp_event; |
|---|
| 1037 | + const char *name; |
|---|
| 1038 | + |
|---|
| 1039 | + list_for_each_entry(tp_event, &ftrace_events, list) { |
|---|
| 1040 | + if (!tp_event->class->system || |
|---|
| 1041 | + strcmp(system, tp_event->class->system)) |
|---|
| 1042 | + continue; |
|---|
| 1043 | + name = trace_event_name(tp_event); |
|---|
| 1044 | + if (!name || strcmp(event_name, name)) |
|---|
| 1045 | + continue; |
|---|
| 1046 | + return tp_event; |
|---|
| 1047 | + } |
|---|
| 1048 | + |
|---|
| 1049 | + return NULL; |
|---|
| 1050 | +} |
|---|
| 1051 | + |
|---|
| 1052 | +int trace_probe_register_event_call(struct trace_probe *tp) |
|---|
| 1053 | +{ |
|---|
| 1054 | + struct trace_event_call *call = trace_probe_event_call(tp); |
|---|
| 1055 | + int ret; |
|---|
| 1056 | + |
|---|
| 1057 | + lockdep_assert_held(&event_mutex); |
|---|
| 1058 | + |
|---|
| 1059 | + if (find_trace_event_call(trace_probe_group_name(tp), |
|---|
| 1060 | + trace_probe_name(tp))) |
|---|
| 1061 | + return -EEXIST; |
|---|
| 1062 | + |
|---|
| 1063 | + ret = register_trace_event(&call->event); |
|---|
| 1064 | + if (!ret) |
|---|
| 1065 | + return -ENODEV; |
|---|
| 1066 | + |
|---|
| 1067 | + ret = trace_add_event_call(call); |
|---|
| 1068 | + if (ret) |
|---|
| 1069 | + unregister_trace_event(&call->event); |
|---|
| 1070 | + |
|---|
| 1071 | + return ret; |
|---|
| 1072 | +} |
|---|
| 1073 | + |
|---|
| 1074 | +int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file) |
|---|
| 1075 | +{ |
|---|
| 1076 | + struct event_file_link *link; |
|---|
| 1077 | + |
|---|
| 1078 | + link = kmalloc(sizeof(*link), GFP_KERNEL); |
|---|
| 1079 | + if (!link) |
|---|
| 1080 | + return -ENOMEM; |
|---|
| 1081 | + |
|---|
| 1082 | + link->file = file; |
|---|
| 1083 | + INIT_LIST_HEAD(&link->list); |
|---|
| 1084 | + list_add_tail_rcu(&link->list, &tp->event->files); |
|---|
| 1085 | + trace_probe_set_flag(tp, TP_FLAG_TRACE); |
|---|
| 1086 | + return 0; |
|---|
| 1087 | +} |
|---|
| 1088 | + |
|---|
| 1089 | +struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp, |
|---|
| 1090 | + struct trace_event_file *file) |
|---|
| 1091 | +{ |
|---|
| 1092 | + struct event_file_link *link; |
|---|
| 1093 | + |
|---|
| 1094 | + trace_probe_for_each_link(link, tp) { |
|---|
| 1095 | + if (link->file == file) |
|---|
| 1096 | + return link; |
|---|
| 1097 | + } |
|---|
| 1098 | + |
|---|
| 1099 | + return NULL; |
|---|
| 1100 | +} |
|---|
| 1101 | + |
|---|
| 1102 | +int trace_probe_remove_file(struct trace_probe *tp, |
|---|
| 1103 | + struct trace_event_file *file) |
|---|
| 1104 | +{ |
|---|
| 1105 | + struct event_file_link *link; |
|---|
| 1106 | + |
|---|
| 1107 | + link = trace_probe_get_file_link(tp, file); |
|---|
| 1108 | + if (!link) |
|---|
| 1109 | + return -ENOENT; |
|---|
| 1110 | + |
|---|
| 1111 | + list_del_rcu(&link->list); |
|---|
| 1112 | + synchronize_rcu(); |
|---|
| 1113 | + kfree(link); |
|---|
| 1114 | + |
|---|
| 1115 | + if (list_empty(&tp->event->files)) |
|---|
| 1116 | + trace_probe_clear_flag(tp, TP_FLAG_TRACE); |
|---|
| 1117 | + |
|---|
| 1118 | + return 0; |
|---|
| 1119 | +} |
|---|
| 1120 | + |
|---|
| 1121 | +/* |
|---|
| 1122 | + * Return the smallest index of different type argument (start from 1). |
|---|
| 1123 | + * If all argument types and name are same, return 0. |
|---|
| 1124 | + */ |
|---|
| 1125 | +int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b) |
|---|
| 1126 | +{ |
|---|
| 1127 | + int i; |
|---|
| 1128 | + |
|---|
| 1129 | + /* In case of more arguments */ |
|---|
| 1130 | + if (a->nr_args < b->nr_args) |
|---|
| 1131 | + return a->nr_args + 1; |
|---|
| 1132 | + if (a->nr_args > b->nr_args) |
|---|
| 1133 | + return b->nr_args + 1; |
|---|
| 1134 | + |
|---|
| 1135 | + for (i = 0; i < a->nr_args; i++) { |
|---|
| 1136 | + if ((b->nr_args <= i) || |
|---|
| 1137 | + ((a->args[i].type != b->args[i].type) || |
|---|
| 1138 | + (a->args[i].count != b->args[i].count) || |
|---|
| 1139 | + strcmp(a->args[i].name, b->args[i].name))) |
|---|
| 1140 | + return i + 1; |
|---|
| 1141 | + } |
|---|
| 1142 | + |
|---|
| 1143 | + return 0; |
|---|
| 1144 | +} |
|---|
| 1145 | + |
|---|
| 1146 | +bool trace_probe_match_command_args(struct trace_probe *tp, |
|---|
| 1147 | + int argc, const char **argv) |
|---|
| 1148 | +{ |
|---|
| 1149 | + char buf[MAX_ARGSTR_LEN + 1]; |
|---|
| 1150 | + int i; |
|---|
| 1151 | + |
|---|
| 1152 | + if (tp->nr_args < argc) |
|---|
| 1153 | + return false; |
|---|
| 1154 | + |
|---|
| 1155 | + for (i = 0; i < argc; i++) { |
|---|
| 1156 | + snprintf(buf, sizeof(buf), "%s=%s", |
|---|
| 1157 | + tp->args[i].name, tp->args[i].comm); |
|---|
| 1158 | + if (strcmp(buf, argv[i])) |
|---|
| 1159 | + return false; |
|---|
| 1160 | + } |
|---|
| 1161 | + return true; |
|---|
| 1162 | +} |
|---|