tracing: Fixes for 5.14-rc4
Subsystems (4)
Steven Rostedt
maintainercover tracing: Fixes for 5.14-rc4
Various tracing fixes:
- Fix NULL pointer dereference caused by an error path
- Give histogram calculation fields a size, otherwise it breaks synthetic creation based on them.
- Reject strings being used for number calculations.
- Fix recordmcount.pl warning on llvm building RISC-V allmodconfig
- Fix the draw_functrace.py script to handle the new trace output
- Fix warning of smp_processor_id() in preemptible code
Hui Su (1):
scripts/tracing: fix the bug that can't parse raw_trace_func
Kamal Agrawal (1):
tracing: Fix NULL pointer dereference in start_creating
Masami Hiramatsu (1):
tracing: Reject string operand in the histogram expression
Nathan Chancellor (1):
scripts/recordmcount.pl: Remove check_objcopy() and $can_use_local
Steven Rostedt (VMware) (2):
tracing / histogram: Give calculation hist_fields a size
tracing: Quiet smp_processor_id() use in preemptable warning in hwlat
----
Makefile | 1 - kernel/trace/trace.c | 4 +++- kernel/trace/trace_events_hist.c | 24 ++++++++++++++++++++++- kernel/trace/trace_hwlat.c | 2 +- scripts/recordmcount.pl | 40 --------------------------------------- scripts/tracing/draw_functrace.py | 6 +++--- 6 files changed, 30 insertions(+), 47 deletions(-)
Steven Rostedt
maintainerPATCH 1/6 tracing: Fix NULL pointer dereference in start_creating
From: Kamal Agrawal <[email protected]>
The event_trace_add_tracer() can fail. In this case, it leads to a crash in start_creating with below call stack. Handle the error scenario properly in trace_array_create_dir.
Call trace: down_write+0x7c/0x204 start_creating.25017+0x6c/0x194 tracefs_create_file+0xc4/0x2b4 init_tracer_tracefs+0x5c/0x940 trace_array_create_dir+0x58/0xb4 trace_array_create+0x1bc/0x2b8 trace_array_get_by_name+0xdc/0x18c
--- kernel/trace/trace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/trace.c +3 -1
@@ -9135,8 +9135,10 @@ static int trace_array_create_dir(struct trace_array *tr)return -EINVAL ; ret =event_trace_add_tracer (tr->dir, tr); -if (ret) +if (ret) {tracefs_remove (tr->dir); +return ret; + }init_tracer_tracefs (tr, tr->dir);__update_tracer_options (tr);
Signature · 1 line
2.30.2
Steven Rostedt
maintainerPATCH 2/6 tracing / histogram: Give calculation hist_fields a size
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
When working on my user space applications, I found a bug in the synthetic event code where the automated synthetic event field was not matching the event field calculation it was attached to. Looking deeper into it, it was because the calculation hist_field was not given a size.
The synthetic event fields are matched to their hist_fields either by having the field have an identical string type, or if that does not match, then the size and signed values are used to match the fields.
The problem arose when I tried to match a calculation where the fields were "unsigned int". My tool created a synthetic event of type "u32". But it failed to match. The string was:
diff=field1-field2:onmatch(event).trace(synth,$diff)
Adding debugging into the kernel, I found that the size of "diff" was 0. And since it was given "unsigned int" as a type, the histogram fallback code used size and signed. The signed matched, but the size of u32 (4) did not match zero, and the event failed to be created.
This can be worse if the field you want to match is not one of the acceptable fields for a synthetic event. As event fields can have any type that is supported in Linux, this can cause an issue. For example, if a type is an enum. Then there's no way to use that with any calculations.
Have the calculation field simply take on the size of what it is calculating.
--- kernel/trace/trace_events_hist.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/trace/trace_events_hist.c +4 -0
@@ -2287,6 +2287,10 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, expr->operands[0 ] = operand1; expr->operands[1 ] = operand2; + +/* The operand sizes should be the same, so just pick one */ + expr->size = operand1->size; + expr->operator = field_op; expr->name =expr_str (expr,0 ); expr->type =kstrdup (operand1->type,GFP_KERNEL );
Signature · 1 line
2.30.2
Steven Rostedt
maintainerPATCH 3/6 tracing: Reject string operand in the histogram expression
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Since the string type can not be the target of the addition / subtraction operation, it must be rejected. Without this fix, the string type silently converted to digits.
--- kernel/trace/trace_events_hist.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
kernel/trace/trace_events_hist.c +19 -1
@@ -65,7 +65,8 @@C (INVALID_SORT_MODIFIER ,"Invalid sort modifier" ), \C (EMPTY_SORT_FIELD ,"Empty sort field" ), \C (TOO_MANY_SORT_FIELDS ,"Too many sort fields (Max = 2)" ), \ -C (INVALID_SORT_FIELD ,"Sort field must be a key or a val" ), +C (INVALID_SORT_FIELD ,"Sort field must be a key or a val" ), \ +C (INVALID_STR_OPERAND ,"String type can not be an operand in expression" ), #undef C #define C(a, b) HIST_ERR_##a
@@ -2156,6 +2157,13 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data, ret =PTR_ERR (operand1); goto free; } +if (operand1->flags &HIST_FIELD_FL_STRING ) { +/* String type can not be the operand of unary operator. */ +hist_err (file->tr,HIST_ERR_INVALID_STR_OPERAND ,errpos (str)); +destroy_hist_field (operand1,0 ); + ret = -EINVAL ; + goto free; + } expr->flags |= operand1->flags & (HIST_FIELD_FL_TIMESTAMP |HIST_FIELD_FL_TIMESTAMP_USECS );
@@ -2257,6 +2265,11 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, operand1 =NULL ; goto free; } +if (operand1->flags &HIST_FIELD_FL_STRING ) { +hist_err (file->tr,HIST_ERR_INVALID_STR_OPERAND ,errpos (operand1_str)); + ret = -EINVAL ; + goto free; + }/* rest of string could be another expression e.g. b+c in a+b+c */ operand_flags =0 ;
@@ -2266,6 +2279,11 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, operand2 =NULL ; goto free; } +if (operand2->flags &HIST_FIELD_FL_STRING ) { +hist_err (file->tr,HIST_ERR_INVALID_STR_OPERAND ,errpos (str)); + ret = -EINVAL ; + goto free; + } ret =check_expr_operands (file->tr, operand1, operand2);if (ret)
Signature · 1 line
2.30.2
Steven Rostedt
maintainerPATCH 4/6 scripts/recordmcount.pl: Remove check_objcopy() and $can_use_local
In reply to Steven RostedtFrom: Nathan Chancellor <[email protected]>
When building ARCH=riscv allmodconfig with llvm-objcopy, the objcopy version warning from this script appears:
WARNING: could not find objcopy version or version is less than 2.17.
Local function references are disabled.
The check_objcopy() function in scripts/recordmcount.pl is set up to parse GNU objcopy's version string, not llvm-objcopy's, which triggers the warning.
Commit 799c43415442 ("kbuild: thin archives make default for all archs") made binutils 2.20 mandatory and commit ba64beb17493 ("kbuild: check the minimum assembler version in Kconfig") enforces this at configuration time so just remove check_objcopy() and $can_use_local instead, assuming --globalize-symbol is always available.
llvm-objcopy has supported --globalize-symbol since LLVM 7.0.0 in 2018 and the minimum version for building the kernel with LLVM is 10.0.1 so there is no issue introduced:
--- Makefile | 1 - scripts/recordmcount.pl | 40 ---------------------------------------- 2 files changed, 41 deletions(-)
Makefile +0 -1
@@ -546,7 +546,6 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ PHONY += scripts_basic scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic - $(Q)rm -f .tmp_quiet_recordmcount PHONY += outputmakefile ifdef building_out_of_srctree
scripts/recordmcount.pl +0 -40
@@ -173,39 +173,6 @@ my $mcount_regex; # Find the call site to mcount (return offset) my $mcount_adjust; # Address adjustment to mcount offset my $alignment; # The .align value to use for $mcount_section my $section_type; # Section header plus possible alignment command -my $can_use_local = 0; # If we can use local function references - -# Shut up recordmcount if user has older objcopy -my $quiet_recordmcount = ".tmp_quiet_recordmcount"; -my $print_warning = 1; -$print_warning = 0 if ( -f $quiet_recordmcount); - -## -# check_objcopy - whether objcopy supports --globalize-symbols -# -# --globalize-symbols came out in 2.17, we must test the version -# of objcopy, and if it is less than 2.17, then we can not -# record local functions. -sub check_objcopy -{ - open (IN, "$objcopy --version |") or die "error running $objcopy"; - while (<IN>) { - if (/objcopy.*\s(\d+)\.(\d+)/) { - $can_use_local = 1 if ($1 > 2 || ($1 == 2 && $2 >= 17)); - last; - } - } - close (IN); - - if (!$can_use_local && $print_warning) { - print STDERR "WARNING: could not find objcopy version or version " . - "is less than 2.17.\n" . - "\tLocal function references are disabled.\n"; - open (QUIET, ">$quiet_recordmcount"); - printf QUIET "Disables the warning from recordmcount.pl\n"; - close QUIET; - } -} if ($arch =~ /(x86(_64)?)|(i386)/) { if ($bits == 64) {
@@ -434,8 +401,6 @@ if ($filename =~ m,^(.*)(\.\S),) { my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s"; my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o"; -check_objcopy(); - # # Step 1: find all the local (static functions) and weak symbols. # 't' is local, 'w/W' is weak
@@ -473,11 +438,6 @@ sub update_funcs # is this function static? If so, note this fact. if (defined $locals{$ref_func}) { - - # only use locals if objcopy supports globalize-symbols - if (!$can_use_local) { - return; - } $convert{$ref_func} = 1; }
Signature · 1 line
2.30.2
Steven Rostedt
maintainerPATCH 5/6 scripts/tracing: fix the bug that cant parse raw_trace_func
In reply to Steven RostedtFrom: Hui Su <[email protected]>
Since commit 77271ce4b2c0 ("tracing: Add irq, preempt-count and need resched info to default trace output"), the default trace output format has been changed to:
<idle>-0 [009] d.h. 22420.068695: _raw_spin_lock_irqsave <-hrtimer_interrupt
<idle>-0 [000] ..s. 22420.068695: _nohz_idle_balance <-run_rebalance_domains
<idle>-0 [011] d.h. 22420.068695: account_process_tick <-update_process_timesorigin trace output format:(before v3.2.0)
# tracer: nop
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
migration/0-6 [000] 50.025810: rcu_note_context_switch <-__schedule
migration/0-6 [000] 50.025812: trace_rcu_utilization <-rcu_note_context_switch
migration/0-6 [000] 50.025813: rcu_sched_qs <-rcu_note_context_switch
migration/0-6 [000] 50.025815: rcu_preempt_qs <-rcu_note_context_switch
migration/0-6 [000] 50.025817: trace_rcu_utilization <-rcu_note_context_switch
migration/0-6 [000] 50.025818: debug_lockdep_rcu_enabled <-__schedule
migration/0-6 [000] 50.025820: debug_lockdep_rcu_enabled <-__scheduleThe draw_functrace.py(introduced in v2.6.28) can't parse the new version format trace_func, So we need modify draw_functrace.py to adapt the new version trace output format.
--- scripts/tracing/draw_functrace.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
scripts/tracing/draw_functrace.py +3 -3
@@ -17,7 +17,7 @@ Usage: $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func Wait some times but not too much, the script is a bit slow. Break the pipe (Ctrl + Z) - $ scripts/draw_functrace.py < raw_trace_func > draw_functrace + $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace Then you have your drawn trace in draw_functrace """
@@ -103,10 +103,10 @@ def parseLine(line): line = line.strip() if line.startswith("#"): raise CommentLineException - m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line) + m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line) if m is None: raise BrokenLineException - return (m.group(1), m.group(2), m.group(3)) + return (m.group(2), m.group(3), m.group(4)) def main():
Signature · 1 line
2.30.2
Steven Rostedt
maintainerPATCH 6/6 tracing: Quiet smp_processor_id() use in preemptable warning in hwlat
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
The hardware latency detector (hwlat) has a mode that it runs one thread across CPUs. The logic to move from the currently running CPU to the next one in the list does a smp_processor_id() to find where it currently is. Unfortunately, it's done with preemption enabled, and this triggers a warning for using smp_processor_id() in a preempt enabled section.
As it is only using smp_processor_id() to get information on where it currently is in order to simply move it to the next CPU, it doesn't really care if it got moved in the mean time. It will simply balance out later if such a case arises.
Switch smp_processor_id() to raw_smp_processor_id() to quiet that warning.
--- kernel/trace/trace_hwlat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_hwlat.c +1 -1
@@ -327,7 +327,7 @@ static void move_to_next_cpu(void)get_online_cpus ();cpumask_and (current_mask, cpu_online_mask, tr->tracing_cpumask); - next_cpu =cpumask_next (smp_processor_id (), current_mask); + next_cpu =cpumask_next (raw_smp_processor_id (), current_mask);put_online_cpus ();if (next_cpu >= nr_cpu_ids)
Signature · 1 line
2.30.2