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
5858 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
5959 FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
6060 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
61− (x8/x16/x32/x64), "string", "ustring" and bitfield
62− are supported.
61+ (x8/x16/x32/x64), "string", "ustring", "symbol", "symstr"
62+ and bitfield are supported.
6363
6464 (\*1) only for the probe on function entry (offs == 0).
6565 (\*2) only for return probe.
@@ -96,6 +96,10 @@ offset, and container-size (usually 32). The syntax is:: · 30 unmodified lines
9696
9797 Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
9898 which shows given pointer in "symbol+offset" style.
99+On 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.
101+With 'symstr' type, you can filter the event with wildcard pattern of the
102+symbols, and you don't need to solve symbol name by yourself.
99103 For $comm, the default type is "string"; any other type is invalid.
100104
101105 .. _user_mem_access:
kernel/trace/trace.c+1−1
@@ -5608,7 +5608,7 @@ static const char readme_msg[] = · 5607 unmodified lines
56085608 "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
56095609 "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
56105610 "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
5611− "\t <type>\\[<array-size>\\]\n"
5611+ "\t symstr, <type>\\[<array-size>\\]\n"
56125612 #ifdef CONFIG_HIST_TRIGGERS
56135613 "\t field: <stype> <name>;\n"
56145614 "\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
7676 /* Fetch type information table */
7777 static const struct fetch_type probe_fetch_types[] = {
7878 /* Special types */
79− __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
79+ __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, 1,
8080 "__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,
8284 "__data_loc char[]"),
8385 /* Basic types */
8486 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
662664
663665 ret = -EINVAL;
664666 /* Store operation */
665− if (!strcmp(parg->type->name, "string") ||
666− !strcmp(parg->type->name, "ustring")) {
667− if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
668− code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
669− code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
670− trace_probe_log_err(offset + (t ? (t - arg) : 0),
671− BAD_STRING);
672− goto fail;
667+ if (parg->type->is_string) {
668+ if (!strcmp(parg->type->name, "symstr")) {
669+ if (code->op != FETCH_OP_REG && code->op != FETCH_OP_STACK &&
670+ code->op != FETCH_OP_RETVAL && code->op != FETCH_OP_ARG &&
671+ code->op != FETCH_OP_DEREF && code->op != FETCH_OP_TP_ARG) {
672+ trace_probe_log_err(offset + (t ? (t - arg) : 0),
673+ BAD_SYMSTRING);
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+ }
673684 }
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 ||
675687 code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||
676688 parg->count) {
677689 /*
@@ -679,6 +691,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, · 1 unmodified line
679691 * must be kept, and if parg->count != 0, this is an
680692 * array of string pointers instead of string address
681693 * itself.
694+ * For the symstr, it doesn't need to dereference, thus
695+ * it just get the value.
682696 */
683697 code++;
684698 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
690704 if (!strcmp(parg->type->name, "ustring") ||
691705 code->op == FETCH_OP_UDEREF)
692706 code->op = FETCH_OP_ST_USTRING;
707+ else if (!strcmp(parg->type->name, "symstr"))
708+ code->op = FETCH_OP_ST_SYMSTR;
693709 else
694710 code->op = FETCH_OP_ST_STRING;
695711 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
919935 for (i = 0; i < tp->nr_args; i++) {
920936 parg = tp->args + i;
921937 if (parg->count) {
922− if ((strcmp(parg->type->name, "string") == 0) ||
923− (strcmp(parg->type->name, "ustring") == 0))
938+ if (parg->type->is_string)
924939 fmt = ", __get_str(%s[%d])";
925940 else
926941 fmt = ", REC->%s[%d]";
@@ -928,8 +943,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, · 1 unmodified line
928943 pos += snprintf(buf + pos, LEN_OR_ZERO,
929944 fmt, parg->name, j);
930945 } else {
931− if ((strcmp(parg->type->name, "string") == 0) ||
932− (strcmp(parg->type->name, "ustring") == 0))
946+ if (parg->type->is_string)
933947 fmt = ", __get_str(%s)";
934948 else
935949 fmt = ", REC->%s";
kernel/trace/trace_probe.h+11−5
@@ -98,6 +98,7 @@ enum fetch_op { · 97 unmodified lines
9898 FETCH_OP_ST_UMEM, /* Mem: .offset, .size */
9999 FETCH_OP_ST_STRING, /* String: .offset, .size */
100100 FETCH_OP_ST_USTRING, /* User String: .offset, .size */
101+ FETCH_OP_ST_SYMSTR, /* Kernel Symbol String: .offset, .size */
101102 // Stage 4 (modify) op
102103 FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */
103104 // Stage 5 (loop) op
@@ -133,7 +134,8 @@ struct fetch_insn { · 29 unmodified lines
133134 struct fetch_type {
134135 const char *name; /* Name of type */
135136 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 */
137139 print_type_func_t print; /* Print functions */
138140 const char *fmt; /* Format string */
139141 const char *fmttype; /* Name in format file */
@@ -177,16 +179,19 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol); · 37 unmodified lines
177179 #define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)
178180 #define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)
179181
180−#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
181− {.name = _name, \
182+#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, str, _fmttype) \
183+ {.name = _name, \
182184 .size = _size, \
183− .is_signed = sign, \
185+ .is_signed = (bool)sign, \
186+ .is_string = (bool)str, \
184187 .print = PRINT_TYPE_FUNC_NAME(ptype), \
185188 .fmt = PRINT_TYPE_FMT_NAME(ptype), \
186189 .fmttype = _fmttype, \
187190 }
191+
192+/* Non string types can use these macros */
188193 #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)
190195 #define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \
191196 _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)
192197
@@ -431,6 +436,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, · 238 unmodified lines
431436 C(ARRAY_TOO_BIG, "Array number is too big"), \
432437 C(BAD_TYPE, "Unknown type is specified"), \
433438 C(BAD_STRING, "String accepts only memory argument"), \
439+ C(BAD_SYMSTRING, "Symbol String doesn't accept data/userdata"), \
434440 C(BAD_BITFIELD, "Invalid bitfield"), \
435441 C(ARG_NAME_TOO_LONG, "Argument name is too long"), \
436442 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
6767 static nokprobe_inline int
6868 probe_mem_read_user(void *dest, void *src, size_t size);
6969
70+static nokprobe_inline int
71+fetch_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+ */
87+static nokprobe_inline int
88+fetch_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+
70101 /* From the 2nd stage, routine is same */
71102 static nokprobe_inline int
72103 process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
@@ -99,16 +130,22 @@ stage2: · 26 unmodified lines
99130 stage3:
100131 /* 3rd stage: store value to buffer */
101132 if (unlikely(!dest)) {
102− if (code->op == FETCH_OP_ST_STRING) {
133+ switch (code->op) {
134+ case FETCH_OP_ST_STRING:
103135 ret = fetch_store_strlen(val + code->offset);
104136 code++;
105137 goto array;
106− } else if (code->op == FETCH_OP_ST_USTRING) {
138+ case FETCH_OP_ST_USTRING:
107139 ret += fetch_store_strlen_user(val + code->offset);
108140 code++;
109141 goto array;
110− } else
142+ case FETCH_OP_ST_SYMSTR:
143+ ret += fetch_store_symstrlen(val + code->offset);
144+ code++;
145+ goto array;
146+ default:
111147 return -EILSEQ;
148+ }
112149 }
113150
114151 switch (code->op) {
@@ -129,6 +166,10 @@ stage3: · 14 unmodified lines
129166 loc = *(u32 *)dest;
130167 ret = fetch_store_string_user(val + code->offset, dest, base);
131168 break;
169+ case FETCH_OP_ST_SYMSTR:
170+ loc = *(u32 *)dest;
171+ ret = fetch_store_symstring(val + code->offset, dest, base);
172+ break;
132173 default:
133174 return -EILSEQ;
134175 }