Re: [PATCH] dtc: create tool to diff device trees

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Thu, Dec 31, 2015 at 3:12 AM, Frank Rowand <frowand.list@xxxxxxxxx> wrote:
> From: Frank Rowand <frank.rowand@xxxxxxxxxxxxxx>
>
> Create script to diff device trees.
>
> The device tree can be in any of the forms recognized by the dtc compiler:
>   - source
>   - binary blob
>   - file system tree (from /proc/devicetree)
>
> If the device tree is a source file, then it is pre-processed in the
> same way as it would be when built in the linux kernel source tree
> before diffing.

In general, I'd like to see some of this move to dtc and the kernel
dependencies minimized.

>
> Signed-off-by: Frank Rowand <frank.rowand@xxxxxxxxxxxxxx>
> ---
>
> Tools to develop and debug device tree are somewhat inadequate.  This is a
> small step in improving the situation.
>
> Rationale for and examples of using the script are provided in slides
> 1 - 78 of the elce 2015 presentation "Solving Device Tree Issues",
> which can be found at:
>
>    http://elinux.org/images/0/04/Dt_debugging_elce_2015_151006_0421.pdf
>
> (The script was named dtdiff instead of dtx_diff in the presentation.)
>
>
>  scripts/dtc/dtx_diff |  368 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 368 insertions(+)
>
> Index: b/scripts/dtc/dtx_diff
> ===================================================================
> --- /dev/null
> +++ b/scripts/dtc/dtx_diff
> @@ -0,0 +1,368 @@
> +#! /bin/bash

Add "-e" by default?

> +
> +# Copyright (C) 2015 Frank Rowand
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; version 2 of the License.
> +
> +
> +usage() {
> +
> +       # use spaces instead of tabs in the usage message
> +       cat >&2 <<eod
> +
> +Usage:
> +
> +   `basename $0` DTx
> +        decompile DTx
> +
> +   `basename $0` DTx_1 DTx_2
> +        diff DTx_1 and DTx_2
> +
> +
> +       -f           print full dts in diff (--unified=99999)
> +       -h           synonym for --help
> +       -help        synonym for --help
> +      --help        print this message and exit
> +       -s SRCTREE   linux kernel source tree is at path SRCTREE
> +                        (default is current directory)
> +       -S           linux kernel source tree is at root of current git repo

Can't this be detected? There are some cases of kernel trees which are
not in git.

> +       -u           unsorted, do not sort DTx
> +
> +
> +Each DTx is processed by the dtc compiler to produce a sorted dts source
> +file.  If DTx is a dts source file then it is pre-processed in the same
> +manner as done for the compile of the dts source file in the Linux kernel
> +build system ('#include' and '/include/' directives are processed).
> +
> +If two DTx are provided, the resulting dts source files are diffed.
> +
> +If DTx is a directory, it is treated as a DT subtree, such as
> +  /proc/device-tree.
> +
> +If DTx contains the binary blob magic value in the first four bytes,
> +  it is treated as a binary blob (aka .dtb or FDT).
> +
> +Otherwise DTx is treated as a dts source file (aka .dts).
> +
> +   If this script is not run from the root of the linux source tree,
> +   and DTx utilizes '#include' or '/include/' then the path of the
> +   linux source tree can be provided by '-s SRCTREE' or '-S' so that
> +   include paths will be set properly.
> +
> +   The shell variable \${ARCH} must provide the architecture containing
> +   the dts source file for include paths to be set properly for '#include'
> +   or '/include/' to be processed.
> +
> +   If DTx_1 and DTx_2 are in different architectures, then this script
> +   may not work since \${ARCH} is part of the include path.  Two possible
> +   workarounds:
> +
> +      `basename $0` \\
> +          <(ARCH=arch_of_dtx_1 `basename $0` DTx_1) \\
> +          <(ARCH=arch_of_dtx_2 `basename $0` DTx_2)
> +
> +      `basename $0` ARCH=arch_of_dtx_1 DTx_1 >tmp_dtx_1.dts
> +      `basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts
> +      `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts
> +      rm tmp_dtx_1.dts tmp_dtx_2.dts
> +
> +   If DTx_1 and DTx_2 are in different directories, then this script will
> +   add the path of DTx_1 and DTx_2 to the include paths.  If DTx_2 includes
> +   a local file that exists in both the path of DTx_1 and DTx_2 then the
> +   file in the path of DTx_1 will incorrectly be included.  Possible
> +   workaround:
> +
> +      `basename $0` DTx_1 >tmp_dtx_1.dts
> +      `basename $0` DTx_2 >tmp_dtx_2.dts
> +      `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts
> +      rm tmp_dtx_1.dts tmp_dtx_2.dts
> +
> +eod
> +}
> +
> +
> +compile_to_dts() {
> +
> +       dtx="$1"
> +
> +       if [ -d "${dtx}" ] ; then
> +
> +               # -----  input is file tree
> +
> +               if ( ! ${DTC} -I fs ${dtx} ) ; then
> +                       exit 3
> +               fi
> +
> +       elif [ -f "${dtx}" ] && [ -r "${dtx}" ] ; then
> +
> +               magic=`hexdump -n 4 -e '/1 "%02x"' ${dtx}`
> +               if [ "${magic}" = "d00dfeed" ] ; then

Perhaps this auto-detection should be part of dtc?

> +
> +                       # -----  input is FDT (binary blob)
> +
> +                       if ( ! ${DTC} -I dtb ${dtx} ) ; then
> +                               exit 3
> +                       fi
> +
> +               else
> +
> +                       # -----  input is DTS (source)
> +
> +                       if ( cpp ${cpp_flags} -x assembler-with-cpp ${dtx} | ${DTC} -I dts ) ; then
> +                               return
> +                       fi
> +
> +                       echo ""                                                          >&2
> +                       echo "Possible hints to resolve the above error:"                >&2
> +                       echo "  (hints might not fix the problem)"                       >&2
> +
> +                       hint_given=0
> +
> +                       if [ "${ARCH}" = "" ] ; then
> +                               hint_given=1
> +                               echo ""                                                      >&2
> +                               echo "  shell variable \$ARCH not set"                       >&2
> +                       fi
> +
> +                       dtx_arch=`echo "/${dtx}" | sed -e 's|.*/arch/||' -e 's|/.*||'`
> +
> +                       if [ "${dtx_arch}" != ""  -a "${dtx_arch}" != "${ARCH}" ] ; then
> +                               hint_given=1
> +                               echo ""                                                      >&2
> +                               echo "  architecture ${dtx_arch} is in file path, but"       >&2
> +                               echo "  does not match shell variable \$ARCH (${ARCH})"      >&2
> +                       fi
> +
> +                       if [ ! -d ${srctree}/arch/${ARCH} ] ; then
> +                               hint_given=1
> +                               echo ""                                                      >&2
> +                               echo "  ${srctree}/arch/${ARCH}/ does not exist"             >&2
> +                               echo "  Is \$ARCH='${ARCH}' correct?"                        >&2
> +                               echo "  Possible fix: use '-s' option"                       >&2
> +
> +                               git_root=`git rev-parse --show-toplevel 2>/dev/null`
> +                               if [ -d ${git_root}/arch/ ] ; then
> +                                       echo "  Possible fix: use '-S' option"                   >&2
> +                               fi
> +                       fi
> +
> +                       if [ $hint_given = 0 ] ; then
> +                               echo ""                                                      >&2
> +                               echo "  No hints available."                                 >&2
> +                       fi
> +
> +                       echo ""                                                          >&2
> +
> +                       exit 3
> +
> +               fi
> +       else
> +               echo ""                                                              >&2
> +               echo "ERROR: ${dtx} does not exist or is not readable"               >&2
> +               echo ""                                                              >&2
> +               exit 2
> +       fi
> +
> +}
> +
> +
> +# -----  start of script
> +
> +cmd_diff=0
> +diff_flags="-u"
> +dtx_file_1=""
> +dtx_file_2=""
> +dtc_sort="-s"
> +help=0
> +srctree=""
> +
> +
> +while [ $# -gt 0 ] ; do
> +
> +       case $1 in
> +
> +       -f )
> +               diff_flags="--unified=999999"
> +               shift
> +               ;;
> +
> +       -h | -help | --help )
> +               help=1
> +               shift
> +               ;;
> +
> +       -s )
> +               srctree="$2"
> +               shift 2
> +               ;;
> +
> +       -S )
> +               git_root=`git rev-parse --show-toplevel 2>/dev/null`
> +               srctree="${git_root}"
> +               shift
> +               ;;
> +
> +       -u )
> +               dtc_sort=""
> +               shift
> +               ;;
> +
> +       *)
> +               if [ "${dtx_file_1}"  = "" ] ; then
> +                       dtx_file_1="$1"
> +               elif [ "${dtx_file_2}" = "" ] ; then
> +                       dtx_file_2="$1"
> +               else
> +                       echo ""                                                          >&2
> +                       echo "ERROR: Unexpected parameter: $1"                           >&2
> +                       echo ""                                                          >&2
> +                       exit 2
> +               fi
> +               shift
> +               ;;
> +
> +       esac
> +
> +done
> +
> +if [ "${srctree}" = "" ] ; then
> +       srctree="."
> +fi
> +
> +if [ "${dtx_file_2}" != "" ]; then
> +       cmd_diff=1
> +fi
> +
> +if (( ${help} )) ; then
> +       usage
> +       exit 1
> +fi
> +
> +# this must follow check for ${help}
> +if [ "${dtx_file_1}" = "" ]; then
> +       echo ""                                                                  >&2
> +       echo "ERROR: parameter DTx required"                                     >&2
> +       echo ""                                                                  >&2
> +       exit 2
> +fi
> +
> +
> +# -----  prefer dtc from linux kernel, allow fallback to dtc in $PATH
> +
> +if [ "${KBUILD_OUTPUT:0:2}" = ".." ] ; then
> +       __KBUILD_OUTPUT="${srctree}/${KBUILD_OUTPUT}"
> +elif [ "${KBUILD_OUTPUT}" = "" ] ; then
> +       __KBUILD_OUTPUT="."
> +else
> +       __KBUILD_OUTPUT="${KBUILD_OUTPUT}"
> +fi
> +
> +DTC="${__KBUILD_OUTPUT}/scripts/dtc/dtc"
> +
> +if [ ! -x ${DTC} ] ; then
> +       __DTC="dtc"
> +       if ( ! which ${__DTC} >/dev/null ) ; then
> +
> +               # use spaces instead of tabs in the error message
> +               cat >&2 <<eod
> +
> +ERROR: unable to find a 'dtc' program
> +
> +   Preferred 'dtc' (built from Linux kernel source tree) was not found or
> +   is not executable.
> +
> +      'dtc' is: ${DTC}
> +
> +      If it does not exist, create it from the root of the Linux source tree:
> +
> +         'make scripts'.
> +
> +      If not at the root of the Linux kernel source tree -s SRCTREE or -S
> +      may need to be specified to find 'dtc'.
> +
> +      If 'O=\${dir}' is specified in your Linux builds, this script requires
> +      'export KBUILD_OUTPUT=\${dir}' or add \${dir}/scripts/dtc to \$PATH
> +      before running.
> +
> +      If \${KBUILD_OUTPUT} is a relative path, then '-s SRCDIR', -S, or run
> +      this script from the root of the Linux kernel source tree is required.
> +
> +   Fallback '${__DTC}' was also not in \${PATH} or is not executable.
> +
> +eod
> +               exit 2
> +       fi
> +       DTC=${__DTC}
> +fi
> +
> +
> +# -----  cpp and dtc flags same as for linux source tree build of .dtb files,
> +#        plus directories of the dtx file(s)
> +
> +dtx_path_1_dtc_include="-i `dirname ${dtx_file_1}`"
> +
> +dtx_path_2_dtc_include=""
> +if (( ${cmd_diff} )) ; then
> +       dtx_path_2_dtc_include="-i `dirname ${dtx_file_2}`"
> +fi
> +
> +cpp_flags="\
> +       -nostdinc                                              \
> +       -I${srctree}/arch/${ARCH}/boot/dts                     \
> +       -I${srctree}/arch/${ARCH}/boot/dts/include             \
> +       -I${srctree}/arch/${ARCH}/boot/dts/include/dt-bindings \

kernel doesn't use this path. The less dependency on ARCH, the better.
The dependency in the kernel is artificial.

> +       -I${srctree}/drivers/of/testcase-data                  \
> +       -undef -D__DTS__"
> +
> +_dts_makefile=""
> +
> +if [ -f ${srctree}/arch/${ARCH}/boot/dts/Makefile ] ; then
> +       _dts_makefile="${srctree}/arch/${ARCH}/boot/dts/Makefile"
> +elif [ -f ${srctree}/arch/${ARCH}/boot/Makefile ] ; then
> +       # arch/powerpc
> +       _dts_makefile="${srctree}/arch/${ARCH}/boot/Makefile"

We need to move PPC to be in line with other arches rather than
working around it.

> +fi
> +
> +if [ "${_dts_makefile}" != "" ] ; then
> +       arch_dtc_flags=`grep DTC_FLAGS ${_dts_makefile} \

We should just kill DTC_FLAGS being per arch. Plus it is only used for
padding, so it is irrelevant to this tool.

> +               | grep -v "^#"                              \
> +               | sed -e 's|.*=||' `
> +else
> +       arch_dtc_flags=""
> +fi
> +
> +dtc_flags="\
> +       -i ${srctree}/arch/${ARCH}/boot/dts/ \
> +       -i ${srctree}/kernel/dts             \
> +       ${dtx_path_1_dtc_include}            \
> +       ${dtx_path_2_dtc_include}            \
> +       ${arch_dtc_flags}"
> +
> +DTC="${DTC} ${dtc_flags} -O dts -qq -f ${dtc_sort} -o -"
> +
> +
> +# -----  do the diff or decompile
> +
> +if (( ${cmd_diff} )) ; then
> +
> +       diff ${diff_flags} \
> +               <(compile_to_dts "${dtx_file_1}") \
> +               <(compile_to_dts "${dtx_file_2}")
> +
> +else
> +
> +       compile_to_dts "${dtx_file_1}"
> +
> +fi
> +
> +
> +# ==============================================================================
> +# ______________________________________________________________________________
> +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> +# ______________________________________________________________________________
> +#  vi config follows:
> +#
> +#  add "set modelines" to ~/.exrc or ~/.vimrc to set tabs automatically
> +#  ex:set tabstop=4 shiftwidth=4 sts=4:

Kernel standard is 8 characters. I assume that applies to bash files too.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux