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

Showing the changes to kernel (4 of 5 files). Show all

Unified · Split

4 files
  1. kernel/trace/trace.c +1 −1
  2. kernel/trace/trace_probe.c +29 −15
  3. kernel/trace/trace_probe.h +11 −5
  4. kernel/trace/trace_probe_tmpl.h +44 −3
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 }