lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <3c56d148-1133-9371-330b-b2dd56846961@gmail.com>
Date:   Mon, 28 Feb 2022 13:01:39 -0600
From:   Frank Rowand <frowand.list@...il.com>
To:     Rob Herring <robh+dt@...nel.org>
Cc:     devicetree@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 1/1] of: unittest: add program to process EXPECT messages

Hi Rob,

Ping.

-Frank

On 2/1/22 12:14, frowand.list@...il.com wrote:
> From: Frank Rowand <frank.rowand@...y.com>
> 
> If unittest detects a problem it will print a warning or error message
> to the console.  Unittest also triggers warning and error messages from
> other kernel code as a result of intentionally bad unittest data.  This
> has led to confusion as to whether the triggered messages are an
> expected result of a test or whether there is a real problem that is
> independent of unittest.
> 
> EXPECT messages were added to unittest to report each triggered message
> that is expected, resulting in verbose console output.
> 
> scripts/dtc/of_unittest is a new program that processes the EXPECT
> messages to determine whether the triggered messages occurred and
> also removes the excess verbosity of the EXPECT messages.  More
> information is available from 'scripts/dtc/of_unittest_expect --help'.
> 
> Signed-off-by: Frank Rowand <frank.rowand@...y.com>
> ---
> permissions for scripts/dtc/of_unittest should be 770
> 
> I will reply to this message with the usage message from
> 'scripts/dtc/of_unittest_expect --help'.
> 
> I will also reply with examples of raw and processed console logs.
> 
>  Documentation/devicetree/of_unittest.rst |  27 +-
>  scripts/dtc/of_unittest_expect           | 408 +++++++++++++++++++++++
>  2 files changed, 432 insertions(+), 3 deletions(-)
>  create mode 100755 scripts/dtc/of_unittest_expect
> 
> diff --git a/Documentation/devicetree/of_unittest.rst b/Documentation/devicetree/of_unittest.rst
> index 2afe41a37148..8864b52d1195 100644
> --- a/Documentation/devicetree/of_unittest.rst
> +++ b/Documentation/devicetree/of_unittest.rst
> @@ -24,7 +24,28 @@ from the unflattened device tree data structure. This interface is used by
>  most of the device drivers in various use cases.
>  
>  
> -2. Test-data
> +2. Verbose Output (EXPECT)
> +==========================
> +
> +If unittest detects a problem it will print a warning or error message to
> +the console.  Unittest also triggers warning and error messages from other
> +kernel code as a result of intentionally bad unittest data.  This has led
> +to confusion as to whether the triggered messages are an expected result
> +of a test or whether there is a real problem that is independent of unittest.
> +
> +'EXPECT \ : text' (begin) and 'EXPECT / : text' (end) messages have been
> +added to unittest to report that a warning or error is expected.  The
> +begin is printed before triggering the warning or error, and the end is
> +printed after triggering the warning or error.
> +
> +The EXPECT messages result in very noisy console messages that are difficult
> +to read.  The script scripts/dtc/of_unittest_expect was created to filter
> +this verbosity and highlight mismatches between triggered warnings and
> +errors vs expected warnings and errors.  More information is available
> +from 'scripts/dtc/of_unittest_expect --help'.
> +
> +
> +3. Test-data
>  ============
>  
>  The Device Tree Source file (drivers/of/unittest-data/testcases.dts) contains
> @@ -56,7 +77,7 @@ The assembly file is compiled into an object file (testcases.dtb.o), and is
>  linked into the kernel image.
>  
>  
> -2.1. Adding the test data
> +3.1. Adding the test data
>  -------------------------
>  
>  Un-flattened device tree structure:
> @@ -191,7 +212,7 @@ properties are updated to the live tree's node by calling the function
>  update_node_properties().
>  
>  
> -2.2. Removing the test data
> +3.2. Removing the test data
>  ---------------------------
>  
>  Once the test case execution is complete, selftest_data_remove is called in
> diff --git a/scripts/dtc/of_unittest_expect b/scripts/dtc/of_unittest_expect
> new file mode 100755
> index 000000000000..96b12d9ea606
> --- /dev/null
> +++ b/scripts/dtc/of_unittest_expect
> @@ -0,0 +1,408 @@
> +#!/usr/bin/perl
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Copyright 2020, 2022 Sony Corporation
> +#
> +# Author: Frank Rowand
> +
> +# This program is meant to be an aid to reading the verbose output of
> +# on the console log that results from executing the Linux kernel
> +# devicetree unittest (drivers/of/unitest.c).
> +
> +$VUFX = "220201a";
> +
> +use strict 'refs';
> +use strict subs;
> +
> +use Getopt::Long;
> +use Text::Wrap;
> +
> +# strip off everything before final "/"
> +(undef, $script_name) = split(/^.*\//, $0);
> +
> +# following /usr/include/sysexits.h
> +$EX_OK=0;
> +$EX_USAGE=64;
> +
> +
> +#______________________________________________________________________________
> +sub compare {
> +	my ($expect, $got) = @_;
> +	my $expect_next;
> +	my $expect_next_lit;
> +	my $got_next;
> +	my $type;
> +
> +	while ($expect) {
> +
> +		($expect_next, $type) = split(/<</, $expect);
> +		($type) = split(/>>/, $type);
> +		$expect =~ s/^.*?>>//;	# '?' is non-greedy, minimal match
> +
> +		# literal, ignore all metacharacters when used in a regex
> +		$expect_next_lit = quotemeta($expect_next);
> +
> +		$got_next = $got;
> +		$got_next =~ s/^($expect_next_lit).*/\1/;
> +		$got       =~ s/^$expect_next_lit//;
> +
> +		if ($expect_next ne $got_next) {
> +			return 0;
> +		}
> +
> +		if ($type eq "int") {
> +			if ($got =~ /^[+-]*[0-9]+/) {
> +				$got =~ s/^[+-]*[0-9]+//;
> +			} else {
> +				return 0;
> +			}
> +		} elsif ($type eq "hex") {
> +			if ($got =~ /^(0x)*[0-9a-f]+/) {
> +				$got =~ s/^(0x)*[0-9a-f]+//;
> +			} else {
> +				return 0;
> +			}
> +		} elsif ($type eq "") {
> +			if ($expect_next ne $got_next) {
> +				return 0;
> +			} else {
> +				return 1;
> +			}
> +		} else {
> +			$internal_err++;
> +			print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n";
> +			return 0;
> +		}
> +
> +	}
> +
> +	# should not get here
> +	$internal_err++;
> +	print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n";
> +
> +	return 0;
> +}
> +
> +
> +#______________________________________________________________________________
> +sub usage {
> +
> +# ***** when editing, be careful to not put tabs in the string printed:
> +
> +	print STDERR
> +"
> +usage:
> +
> +  $script_name CONSOLE_LOG
> +
> +     -h                print program usage
> +    --help             print program usage
> +    --hide-expect      suppress output of EXPECTed lines
> +    --line-num         report line number of CONSOLE_LOG
> +    --no-expect-stats  do not report EXPECT statistics
> +    --no-strip-ts      do not strip leading console timestamps
> +    --verbose          do not suppress EXPECT begin and end lines
> +    --version          print program version and exit
> +
> +
> +  Process a console log for EXPECTed test related messages to either
> +  highlight expected devicetree unittest related messages or suppress
> +  the messages.  Leading console timestamps will be stripped.
> +
> +  Various unittests may trigger kernel messages from outside the
> +  unittest code.  The unittest annotates that it expects the message
> +  to occur with an 'EXPECT \\ : text' (begin) before triggering the
> +  message, and an 'EXPECT / : text' (end) after triggering the message.
> +
> +  If an expected message does not occur, that will be reported.
> +
> +  For each expected message, the 'EXPECT \\ : text' (begin) and
> +  'EXPECT / : text' (end), 'text' will contain the message text.
> +
> +  If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain
> +  matching 'text', that will be reported.
> +
> +  If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the
> +  reverse order of the corresponding 'EXPECT \\' (begin) lines.
> +
> +  'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can
> +  contain special patterns in 'text':
> +
> +     <<int>> matches: [+-]*[0-9]+
> +     <<hex>> matches: (0x)*[0-9a-f]+
> +
> +  'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed.
> +
> +  A prefix is added to every line of output:
> +
> +    'ok ' Line matches an enclosing EXPECT begin/end pair
> +
> +    '** ' Line reports $script_name warning or error
> +
> +    '-> ' Line reports start or end of the unittests
> +
> +    '>> ' Line reports a unittest test FAIL
> +
> +    '   ' Lines that are not otherwise prefixed
> +
> +  Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR.
> +
> +  Known Issues:
> +
> +    --line-num causes the CONSOLE_LOG line number to be printed in 4 columns.
> +       If CONSOLE_LOG contains more than 9999 lines then more columns will be
> +       used to report the line number for lines greater than 9999 (eg for
> +       lines 10000 - 99999, 5 columns will be used).
> +";
> +
> +	return {};
> +}
> +
> +#______________________________________________________________________________
> +#______________________________________________________________________________
> +
> +if (!GetOptions(
> +	"h"               => \$help,
> +	"help"            => \$help,
> +	"hide-expect"     => \$hide_expect,
> +	"line-num"        => \$print_line_num,
> +	"no-expect-stats" => \$no_expect_stats,
> +	"no-strip-ts"     => \$no_strip_ts,
> +	"verbose"         => \$verbose,
> +	"version"         => \$version,
> +	)) {
> +	print STDERR "\n";
> +	print STDERR "ERROR processing command line options\n";
> +	print STDERR "\n";
> +	print STDERR "For help, type '$script_name --help'\n";
> +	print STDERR "\n";
> +
> +	exit $EX_OK;
> +}
> +
> +
> +if ($no_strip_ts) {
> +	$strip_ts = 1;
> +	$no_strip_ts = 0;
> +} else {
> +	$strip_ts = 0;
> +	$no_strip_ts = 1;
> +}
> +
> +
> +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> +if ($help){
> +
> +	&usage;
> +
> +	exit $EX_OK;
> +}
> +
> +
> +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> +
> +if ($version) {
> +	print STDERR "\n$script_name  $VUFX\n\n";
> +	print STDERR "\n";
> +
> +	exit $EX_OK;
> +}
> +
> +
> +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> +if ($#ARGV != 0) {
> +
> +	# Limit input files to exactly one.
> +	#
> +	# 'while ($line = <ARGV>) {' in the code below supports multiple file
> +	# names on the command line, but the EXPECT statistics are reported
> +	# once for all input - it is not an expected use case to generate one
> +	# set of statistics for multiple input files.
> +
> +	print STDERR "\n";
> +	print STDERR "Required arguments: CONSOLE_LOG\n";
> +	print STDERR "\n";
> +
> +	exit $EX_USAGE;
> +}
> +
> +
> +#______________________________________________________________________________
> +
> +# Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end)
> +#
> +# $exp_* are used as regex match patterns,
> +# so '\\\\' in $exp_begin matches a single '\'
> +# quotemeta() does not do the right thing in this case
> +#
> +# $pr_fmt is the prefix that unittest prints for every message
> +
> +$pr_fmt = "### dt-test ### ";
> +$exp_begin = "${pr_fmt}EXPECT \\\\ : ";
> +$exp_end   = "${pr_fmt}EXPECT / : ";
> +
> +
> +$line_num = "";
> +$timestamp = "";
> +
> +LINE:
> +while ($line = <ARGV>) {
> +
> +	chomp $line;
> +
> +	$prefix = "  ";  ## 2 characters
> +
> +
> +	if ($strip_ts) {
> +
> +		$timestamp = $line;
> +
> +		if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) {
> +			($timestamp, $null) = split(/]/, $line);
> +			$timestamp = $timestamp . "] ";
> +
> +		} else {
> +			$timestamp = "";
> +		}
> +	}
> +
> +	$line =~ s/^\[\s*[0-9]+\.[0-9]*\] //;
> +
> +
> +	# -----  find EXPECT begin
> +
> +	if ($line =~ /^\s*$exp_begin/) {
> +		$data = $line;
> +		$data =~ s/^\s*$exp_begin//;
> +		push @begin, $data;
> +
> +		if ($verbose) {
> +			if ($print_line_num) {
> +				$line_num = sprintf("%4s ", $.);
> +			}
> +			printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
> +		}
> +
> +		next LINE;
> +	}
> +
> +
> +	# -----  find EXPECT end
> +
> +	if ($line =~ /^\s*$exp_end/) {
> +		$data = $line;
> +		$data =~ s/^\s*$exp_end//;
> +
> +		if ($verbose) {
> +			if ($print_line_num) {
> +				$line_num = sprintf("%4s ", $.);
> +			}
> +			printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
> +		}
> +
> +		$found = 0;
> +		$no_begin = 0;
> +		if (@found_or_begin > 0) {
> +			$begin = pop @found_or_begin;
> +			if (compare($data, $begin)) {
> +				$found = 1;
> +			}
> +		} elsif (@begin > 0) {
> +			$begin = pop @begin;
> +		} else {
> +			$no_begin = 1;
> +		}
> +
> +		if ($no_begin) {
> +
> +			$expect_missing_begin++;
> +			print "** ERROR: EXPECT end without any EXPECT begin:\n";
> +			print "       end ---> $line\n";
> +
> +		} elsif (! $found) {
> +
> +			if ($print_line_num) {
> +				$line_num = sprintf("%4s ", $.);
> +			}
> +
> +			$expect_not_found++;
> +			printf "** %s%s$script_name WARNING - not found ---> %s\n",
> +					$line_num,  $timestamp, $data;
> +
> +		} elsif (! compare($data, $begin)) {
> +
> +			$expect_missing_end++;
> +			print "** ERROR: EXPECT end does not match EXPECT begin:\n";
> +			print "       begin -> $begin\n";
> +			print "       end ---> $line\n";
> +
> +		} else {
> +
> +			$expect_found++;
> +
> +		}
> +
> +		next LINE;
> +	}
> +
> +
> +	# -----  not an EXPECT line
> +
> +	if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) ||
> +	    ($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ )   ) {
> +		$prefix = "->"; # 2 characters
> +	} elsif ($line =~ /^${pr_fmt}FAIL /) {
> +		$unittest_fail++;
> +		$prefix = ">>"; # 2 characters
> +	}
> +
> +	$found = 0;
> +	foreach $begin (@begin) {
> +		if (compare($begin, $line)) {
> +			$found = 1;
> +			last;
> +		}
> +	}
> +
> +	if ($found) {
> +		$begin = shift @begin;
> +		while (! compare($begin, $line)) {
> +			push @found_or_begin, $begin;
> +			$begin = shift @begin;
> +		}
> +		push @found_or_begin, $line;
> +
> +		if ($hide_expect) {
> +			$suppress_line = 1;
> +			next LINE;
> +		}
> +		$prefix = "ok"; # 2 characters
> +	}
> +
> +
> +	if ($print_line_num) {
> +		$line_num = sprintf("%4s ", $.);
> +	}
> +
> +	printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
> +}
> +
> +if (! $no_expect_stats) {
> +	print  "\n";
> +	print  "** EXPECT statistics:\n";
> +	print  "**\n";
> +	printf "**   EXPECT found          : %4i\n", $expect_found;
> +	printf "**   EXPECT not found      : %4i\n", $expect_not_found;
> +	printf "**   missing EXPECT begin  : %4i\n", $expect_missing_begin;
> +	printf "**   missing EXPECT end    : %4i\n", $expect_missing_end;
> +	printf "**   unittest FAIL         : %4i\n", $unittest_fail;
> +	printf "**   internal error        : %4i\n", $internal_err;
> +}
> +
> +if (@begin) {
> +	print "** ERROR: EXPECT begin without any EXPECT end:\n";
> +	print "          This list may be misleading.\n";
> +	foreach $begin (@begin) {
> +		print "       begin ---> $begin\n";
> +	}
> +}

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ