History

tracing/probes: Add symstr type for dynamic events

Add 'symstr' type for storing the kernel symbol as a string data instead of the symbol address. This allows us to filter the events by wildcard symbol name. e.g. # echo 'e:wqfunc workqueue.workqueue_execute_start symname=$function:symstr' >> dynamic_events # cat events/eprobes/wqfunc/format name: wqfunc ID: 2110 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1; field:__data_loc char[] symname; offset:8; size:4; signed:1; print fmt: " symname=\"%s\"", __get_str(symname) Note that there is already 'symbol' type which just change the print format (so it still stores the symbol address in the tracing ring buffer.) On the other hand, 'symstr' type stores the actual "symbol+offset/size" data as a string. Link: https://lore.kernel.org/all/166679930847.1528100.4124308529180235965.stgit@devnote3/

Masami Hiramatsu (Google) committed 3 years ago

Commit b26a1241 parent 3b7ddab5 files · +91 −26Browse files

Unified · Split

5 files
  1. Documentation/trace/kprobetrace.rst +6 −2
  2. kernel/trace/trace.c +1 −1
  3. kernel/trace/trace_probe.c +29 −15
  4. kernel/trace/trace_probe.h +11 −5
  5. kernel/trace/trace_probe_tmpl.h +44 −3
Documentation/trace/kprobetrace.rst+6−2
@@ -58,8 +58,8 @@ Synopsis of kprobe_events · 57 unmodified lines
58 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.58 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
59 FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types59 FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
60 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types60 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
61 (x8/x16/x32/x64), "string", "ustring" and bitfield61 (x8/x16/x32/x64), "string", "ustring", "symbol", "symstr"
62 are supported.62 and bitfield are supported.
63 63
64 (\*1) only for the probe on function entry (offs == 0).64 (\*1) only for the probe on function entry (offs == 0).
65 (\*2) only for return probe.65 (\*2) only for return probe.
@@ -96,6 +96,10 @@ offset, and container-size (usually 32). The syntax is:: · 30 unmodified lines
96 96
97Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)97Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
98which shows given pointer in "symbol+offset" style.98which shows given pointer in "symbol+offset" style.
99On the other hand, symbol-string type ('symstr') converts the given address to
100"symbol+offset/symbolsize" style and stores it as a null-terminated string.
101With 'symstr' type, you can filter the event with wildcard pattern of the
102symbols, and you don't need to solve symbol name by yourself.
99For $comm, the default type is "string"; any other type is invalid.103For $comm, the default type is "string"; any other type is invalid.
100 104
101.. _user_mem_access:105.. _user_mem_access:
kernel/trace/trace.c+1−1
@@ -5608,7 +5608,7 @@ static const char readme_msg[] = · 5607 unmodified lines
5608 "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"5608 "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
5609 "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"5609 "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
5610 "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n"5610 "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
5611 "\t <type>\\[<array-size>\\]\n"5611 "\t symstr, <type>\\[<array-size>\\]\n"
5612#ifdef CONFIG_HIST_TRIGGERS5612#ifdef CONFIG_HIST_TRIGGERS
5613 "\t field: <stype> <name>;\n"5613 "\t field: <stype> <name>;\n"
5614 "\t stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"5614 "\t stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
kernel/trace/trace_probe.c+29−15
@@ -76,9 +76,11 @@ const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; · 75 unmodified lines
76/* Fetch type information table */76/* Fetch type information table */
77static const struct fetch_type probe_fetch_types[] = {77static const struct fetch_type probe_fetch_types[] = {
78 /* Special types */78 /* Special types */
79 __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,79 __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, 1,
80 "__data_loc char[]"),80 "__data_loc char[]"),
81 __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1,81 __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, 1,
82 "__data_loc char[]"),
83 __ASSIGN_FETCH_TYPE("symstr", string, string, sizeof(u32), 1, 1,
82 "__data_loc char[]"),84 "__data_loc char[]"),
83 /* Basic types */85 /* Basic types */
84 ASSIGN_FETCH_TYPE(u8, u8, 0),86 ASSIGN_FETCH_TYPE(u8, u8, 0),
@@ -662,16 +664,26 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, · 577 unmodified lines
662 664
663 ret = -EINVAL;665 ret = -EINVAL;
664 /* Store operation */666 /* Store operation */
665 if (!strcmp(parg->type->name, "string") ||667 if (parg->type->is_string) {
666 !strcmp(parg->type->name, "ustring")) {668 if (!strcmp(parg->type->name, "symstr")) {
667 if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&669 if (code->op != FETCH_OP_REG && code->op != FETCH_OP_STACK &&
668 code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&670 code->op != FETCH_OP_RETVAL && code->op != FETCH_OP_ARG &&
669 code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {671 code->op != FETCH_OP_DEREF && code->op != FETCH_OP_TP_ARG) {
670 trace_probe_log_err(offset + (t ? (t - arg) : 0),672 trace_probe_log_err(offset + (t ? (t - arg) : 0),
671 BAD_STRING);673 BAD_SYMSTRING);
672 goto fail;674 goto fail;
675 }
676 } else {
677 if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
678 code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
679 code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
680 trace_probe_log_err(offset + (t ? (t - arg) : 0),
681 BAD_STRING);
682 goto fail;
683 }
673 }684 }
674 if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||685 if (!strcmp(parg->type->name, "symstr") ||
686 (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
675 code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||687 code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||
676 parg->count) {688 parg->count) {
677 /*689 /*
@@ -679,6 +691,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, · 1 unmodified line
679 * must be kept, and if parg->count != 0, this is an691 * must be kept, and if parg->count != 0, this is an
680 * array of string pointers instead of string address692 * array of string pointers instead of string address
681 * itself.693 * itself.
694 * For the symstr, it doesn't need to dereference, thus
695 * it just get the value.
682 */696 */
683 code++;697 code++;
684 if (code->op != FETCH_OP_NOP) {698 if (code->op != FETCH_OP_NOP) {
@@ -690,6 +704,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, · 5 unmodified lines
690 if (!strcmp(parg->type->name, "ustring") ||704 if (!strcmp(parg->type->name, "ustring") ||
691 code->op == FETCH_OP_UDEREF)705 code->op == FETCH_OP_UDEREF)
692 code->op = FETCH_OP_ST_USTRING;706 code->op = FETCH_OP_ST_USTRING;
707 else if (!strcmp(parg->type->name, "symstr"))
708 code->op = FETCH_OP_ST_SYMSTR;
693 else709 else
694 code->op = FETCH_OP_ST_STRING;710 code->op = FETCH_OP_ST_STRING;
695 code->size = parg->type->size;711 code->size = parg->type->size;
@@ -919,8 +935,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, · 223 unmodified lines
919 for (i = 0; i < tp->nr_args; i++) {935 for (i = 0; i < tp->nr_args; i++) {
920 parg = tp->args + i;936 parg = tp->args + i;
921 if (parg->count) {937 if (parg->count) {
922 if ((strcmp(parg->type->name, "string") == 0) ||938 if (parg->type->is_string)
923 (strcmp(parg->type->name, "ustring") == 0))
924 fmt = ", __get_str(%s[%d])";939 fmt = ", __get_str(%s[%d])";
925 else940 else
926 fmt = ", REC->%s[%d]";941 fmt = ", REC->%s[%d]";
@@ -928,8 +943,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, · 1 unmodified line
928 pos += snprintf(buf + pos, LEN_OR_ZERO,943 pos += snprintf(buf + pos, LEN_OR_ZERO,
929 fmt, parg->name, j);944 fmt, parg->name, j);
930 } else {945 } else {
931 if ((strcmp(parg->type->name, "string") == 0) ||946 if (parg->type->is_string)
932 (strcmp(parg->type->name, "ustring") == 0))
933 fmt = ", __get_str(%s)";947 fmt = ", __get_str(%s)";
934 else948 else
935 fmt = ", REC->%s";949 fmt = ", REC->%s";
kernel/trace/trace_probe.h+11−5
@@ -98,6 +98,7 @@ enum fetch_op { · 97 unmodified lines
98 FETCH_OP_ST_UMEM, /* Mem: .offset, .size */98 FETCH_OP_ST_UMEM, /* Mem: .offset, .size */
99 FETCH_OP_ST_STRING, /* String: .offset, .size */99 FETCH_OP_ST_STRING, /* String: .offset, .size */
100 FETCH_OP_ST_USTRING, /* User String: .offset, .size */100 FETCH_OP_ST_USTRING, /* User String: .offset, .size */
101 FETCH_OP_ST_SYMSTR, /* Kernel Symbol String: .offset, .size */
101 // Stage 4 (modify) op102 // Stage 4 (modify) op
102 FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */103 FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */
103 // Stage 5 (loop) op104 // Stage 5 (loop) op
@@ -133,7 +134,8 @@ struct fetch_insn { · 29 unmodified lines
133struct fetch_type {134struct fetch_type {
134 const char *name; /* Name of type */135 const char *name; /* Name of type */
135 size_t size; /* Byte size of type */136 size_t size; /* Byte size of type */
136 int is_signed; /* Signed flag */137 bool is_signed; /* Signed flag */
138 bool is_string; /* String flag */
137 print_type_func_t print; /* Print functions */139 print_type_func_t print; /* Print functions */
138 const char *fmt; /* Format string */140 const char *fmt; /* Format string */
139 const char *fmttype; /* Name in format file */141 const char *fmttype; /* Name in format file */
@@ -177,16 +179,19 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol); · 37 unmodified lines
177#define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)179#define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)
178#define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)180#define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)
179 181
180#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \182#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, str, _fmttype) \
181 {.name = _name, \183 {.name = _name, \
182 .size = _size, \184 .size = _size, \
183 .is_signed = sign, \185 .is_signed = (bool)sign, \
186 .is_string = (bool)str, \
184 .print = PRINT_TYPE_FUNC_NAME(ptype), \187 .print = PRINT_TYPE_FUNC_NAME(ptype), \
185 .fmt = PRINT_TYPE_FMT_NAME(ptype), \188 .fmt = PRINT_TYPE_FMT_NAME(ptype), \
186 .fmttype = _fmttype, \189 .fmttype = _fmttype, \
187 }190 }
191
192/* Non string types can use these macros */
188#define _ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \193#define _ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
189 __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, #_fmttype)194 __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, 0, #_fmttype)
190#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \195#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \
191 _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)196 _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)
192 197
@@ -431,6 +436,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, · 238 unmodified lines
431 C(ARRAY_TOO_BIG, "Array number is too big"), \436 C(ARRAY_TOO_BIG, "Array number is too big"), \
432 C(BAD_TYPE, "Unknown type is specified"), \437 C(BAD_TYPE, "Unknown type is specified"), \
433 C(BAD_STRING, "String accepts only memory argument"), \438 C(BAD_STRING, "String accepts only memory argument"), \
439 C(BAD_SYMSTRING, "Symbol String doesn't accept data/userdata"), \
434 C(BAD_BITFIELD, "Invalid bitfield"), \440 C(BAD_BITFIELD, "Invalid bitfield"), \
435 C(ARG_NAME_TOO_LONG, "Argument name is too long"), \441 C(ARG_NAME_TOO_LONG, "Argument name is too long"), \
436 C(NO_ARG_NAME, "Argument name is not specified"), \442 C(NO_ARG_NAME, "Argument name is not specified"), \
kernel/trace/trace_probe_tmpl.h+44−3
@@ -67,6 +67,37 @@ probe_mem_read(void *dest, void *src, size_t size); · 66 unmodified lines
67static nokprobe_inline int67static nokprobe_inline int
68probe_mem_read_user(void *dest, void *src, size_t size);68probe_mem_read_user(void *dest, void *src, size_t size);
69 69
70static nokprobe_inline int
71fetch_store_symstrlen(unsigned long addr)
72{
73 char namebuf[KSYM_SYMBOL_LEN];
74 int ret;
75
76 ret = sprint_symbol(namebuf, addr);
77 if (ret < 0)
78 return 0;
79
80 return ret + 1;
81}
82
83/*
84 * Fetch a null-terminated symbol string + offset. Caller MUST set *(u32 *)buf
85 * with max length and relative data location.
86 */
87static nokprobe_inline int
88fetch_store_symstring(unsigned long addr, void *dest, void *base)
89{
90 int maxlen = get_loc_len(*(u32 *)dest);
91 void *__dest;
92
93 if (unlikely(!maxlen))
94 return -ENOMEM;
95
96 __dest = get_loc_data(dest, base);
97
98 return sprint_symbol(__dest, addr);
99}
100
70/* From the 2nd stage, routine is same */101/* From the 2nd stage, routine is same */
71static nokprobe_inline int102static nokprobe_inline int
72process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,103process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
@@ -99,16 +130,22 @@ stage2: · 26 unmodified lines
99stage3:130stage3:
100 /* 3rd stage: store value to buffer */131 /* 3rd stage: store value to buffer */
101 if (unlikely(!dest)) {132 if (unlikely(!dest)) {
102 if (code->op == FETCH_OP_ST_STRING) {133 switch (code->op) {
134 case FETCH_OP_ST_STRING:
103 ret = fetch_store_strlen(val + code->offset);135 ret = fetch_store_strlen(val + code->offset);
104 code++;136 code++;
105 goto array;137 goto array;
106 } else if (code->op == FETCH_OP_ST_USTRING) {138 case FETCH_OP_ST_USTRING:
107 ret += fetch_store_strlen_user(val + code->offset);139 ret += fetch_store_strlen_user(val + code->offset);
108 code++;140 code++;
109 goto array;141 goto array;
110 } else142 case FETCH_OP_ST_SYMSTR:
143 ret += fetch_store_symstrlen(val + code->offset);
144 code++;
145 goto array;
146 default:
111 return -EILSEQ;147 return -EILSEQ;
148 }
112 }149 }
113 150
114 switch (code->op) {151 switch (code->op) {
@@ -129,6 +166,10 @@ stage3: · 14 unmodified lines
129 loc = *(u32 *)dest;166 loc = *(u32 *)dest;
130 ret = fetch_store_string_user(val + code->offset, dest, base);167 ret = fetch_store_string_user(val + code->offset, dest, base);
131 break;168 break;
169 case FETCH_OP_ST_SYMSTR:
170 loc = *(u32 *)dest;
171 ret = fetch_store_symstring(val + code->offset, dest, base);
172 break;
132 default:173 default:
133 return -EILSEQ;174 return -EILSEQ;
134 }175 }