1246 lines
50 KiB
ReStructuredText
1246 lines
50 KiB
ReStructuredText
|
.. SPDX-License-Identifier: CC-BY-SA-2.0-UK
|
|||
|
|
|||
|
Debugging Tools and Techniques
|
|||
|
******************************
|
|||
|
|
|||
|
The exact method for debugging build failures depends on the nature of
|
|||
|
the problem and on the system's area from which the bug originates.
|
|||
|
Standard debugging practices such as comparison against the last known
|
|||
|
working version with examination of the changes and the re-application
|
|||
|
of steps to identify the one causing the problem are valid for the Yocto
|
|||
|
Project just as they are for any other system. Even though it is
|
|||
|
impossible to detail every possible potential failure, this section
|
|||
|
provides some general tips to aid in debugging given a variety of
|
|||
|
situations.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
A useful feature for debugging is the error reporting tool.
|
|||
|
Configuring the Yocto Project to use this tool causes the
|
|||
|
OpenEmbedded build system to produce error reporting commands as part
|
|||
|
of the console output. You can enter the commands after the build
|
|||
|
completes to log error information into a common database, that can
|
|||
|
help you figure out what might be going wrong. For information on how
|
|||
|
to enable and use this feature, see the
|
|||
|
":ref:`dev-manual/error-reporting-tool:using the error reporting tool`"
|
|||
|
section.
|
|||
|
|
|||
|
The following list shows the debugging topics in the remainder of this
|
|||
|
section:
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:viewing logs from failed tasks`" describes
|
|||
|
how to find and view logs from tasks that failed during the build
|
|||
|
process.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:viewing variable values`" describes how to
|
|||
|
use the BitBake ``-e`` option to examine variable values after a
|
|||
|
recipe has been parsed.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:viewing package information with \`\`oe-pkgdata-util\`\``"
|
|||
|
describes how to use the ``oe-pkgdata-util`` utility to query
|
|||
|
:term:`PKGDATA_DIR` and
|
|||
|
display package-related information for built packages.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:viewing dependencies between recipes and tasks`"
|
|||
|
describes how to use the BitBake ``-g`` option to display recipe
|
|||
|
dependency information used during the build.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:viewing task variable dependencies`" describes
|
|||
|
how to use the ``bitbake-dumpsig`` command in conjunction with key
|
|||
|
subdirectories in the :term:`Build Directory` to determine variable
|
|||
|
dependencies.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:running specific tasks`" describes
|
|||
|
how to use several BitBake options (e.g. ``-c``, ``-C``, and ``-f``)
|
|||
|
to run specific tasks in the build chain. It can be useful to run
|
|||
|
tasks "out-of-order" when trying isolate build issues.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:general BitBake problems`" describes how
|
|||
|
to use BitBake's ``-D`` debug output option to reveal more about what
|
|||
|
BitBake is doing during the build.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:building with no dependencies`"
|
|||
|
describes how to use the BitBake ``-b`` option to build a recipe
|
|||
|
while ignoring dependencies.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:recipe logging mechanisms`"
|
|||
|
describes how to use the many recipe logging functions to produce
|
|||
|
debugging output and report errors and warnings.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:debugging parallel make races`"
|
|||
|
describes how to debug situations where the build consists of several
|
|||
|
parts that are run simultaneously and when the output or result of
|
|||
|
one part is not ready for use with a different part of the build that
|
|||
|
depends on that output.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:debugging with the gnu project debugger (gdb) remotely`"
|
|||
|
describes how to use GDB to allow you to examine running programs, which can
|
|||
|
help you fix problems.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:debugging with the gnu project debugger (gdb) on the target`"
|
|||
|
describes how to use GDB directly on target hardware for debugging.
|
|||
|
|
|||
|
- ":ref:`dev-manual/debugging:other debugging tips`" describes
|
|||
|
miscellaneous debugging tips that can be useful.
|
|||
|
|
|||
|
Viewing Logs from Failed Tasks
|
|||
|
==============================
|
|||
|
|
|||
|
You can find the log for a task in the file
|
|||
|
``${``\ :term:`WORKDIR`\ ``}/temp/log.do_``\ `taskname`.
|
|||
|
For example, the log for the
|
|||
|
:ref:`ref-tasks-compile` task of the
|
|||
|
QEMU minimal image for the x86 machine (``qemux86``) might be in
|
|||
|
``tmp/work/qemux86-poky-linux/core-image-minimal/1.0-r0/temp/log.do_compile``.
|
|||
|
To see the commands :term:`BitBake` ran
|
|||
|
to generate a log, look at the corresponding ``run.do_``\ `taskname` file
|
|||
|
in the same directory.
|
|||
|
|
|||
|
``log.do_``\ `taskname` and ``run.do_``\ `taskname` are actually symbolic
|
|||
|
links to ``log.do_``\ `taskname`\ ``.``\ `pid` and
|
|||
|
``log.run_``\ `taskname`\ ``.``\ `pid`, where `pid` is the PID the task had
|
|||
|
when it ran. The symlinks always point to the files corresponding to the
|
|||
|
most recent run.
|
|||
|
|
|||
|
Viewing Variable Values
|
|||
|
=======================
|
|||
|
|
|||
|
Sometimes you need to know the value of a variable as a result of
|
|||
|
BitBake's parsing step. This could be because some unexpected behavior
|
|||
|
occurred in your project. Perhaps an attempt to :ref:`modify a variable
|
|||
|
<bitbake-user-manual/bitbake-user-manual-metadata:modifying existing
|
|||
|
variables>` did not work out as expected.
|
|||
|
|
|||
|
BitBake's ``-e`` option is used to display variable values after
|
|||
|
parsing. The following command displays the variable values after the
|
|||
|
configuration files (i.e. ``local.conf``, ``bblayers.conf``,
|
|||
|
``bitbake.conf`` and so forth) have been parsed::
|
|||
|
|
|||
|
$ bitbake -e
|
|||
|
|
|||
|
The following command displays variable values after a specific recipe has
|
|||
|
been parsed. The variables include those from the configuration as well::
|
|||
|
|
|||
|
$ bitbake -e recipename
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Each recipe has its own private set of variables (datastore).
|
|||
|
Internally, after parsing the configuration, a copy of the resulting
|
|||
|
datastore is made prior to parsing each recipe. This copying implies
|
|||
|
that variables set in one recipe will not be visible to other
|
|||
|
recipes.
|
|||
|
|
|||
|
Likewise, each task within a recipe gets a private datastore based on
|
|||
|
the recipe datastore, which means that variables set within one task
|
|||
|
will not be visible to other tasks.
|
|||
|
|
|||
|
In the output of ``bitbake -e``, each variable is preceded by a
|
|||
|
description of how the variable got its value, including temporary
|
|||
|
values that were later overridden. This description also includes
|
|||
|
variable flags (varflags) set on the variable. The output can be very
|
|||
|
helpful during debugging.
|
|||
|
|
|||
|
Variables that are exported to the environment are preceded by
|
|||
|
``export`` in the output of ``bitbake -e``. See the following example::
|
|||
|
|
|||
|
export CC="i586-poky-linux-gcc -m32 -march=i586 --sysroot=/home/ulf/poky/build/tmp/sysroots/qemux86"
|
|||
|
|
|||
|
In addition to variable values, the output of the ``bitbake -e`` and
|
|||
|
``bitbake -e`` recipe commands includes the following information:
|
|||
|
|
|||
|
- The output starts with a tree listing all configuration files and
|
|||
|
classes included globally, recursively listing the files they include
|
|||
|
or inherit in turn. Much of the behavior of the OpenEmbedded build
|
|||
|
system (including the behavior of the :ref:`ref-manual/tasks:normal recipe build tasks`) is
|
|||
|
implemented in the :ref:`ref-classes-base` class and the
|
|||
|
classes it inherits, rather than being built into BitBake itself.
|
|||
|
|
|||
|
- After the variable values, all functions appear in the output. For
|
|||
|
shell functions, variables referenced within the function body are
|
|||
|
expanded. If a function has been modified using overrides or using
|
|||
|
override-style operators like ``:append`` and ``:prepend``, then the
|
|||
|
final assembled function body appears in the output.
|
|||
|
|
|||
|
Viewing Package Information with ``oe-pkgdata-util``
|
|||
|
====================================================
|
|||
|
|
|||
|
You can use the ``oe-pkgdata-util`` command-line utility to query
|
|||
|
:term:`PKGDATA_DIR` and display
|
|||
|
various package-related information. When you use the utility, you must
|
|||
|
use it to view information on packages that have already been built.
|
|||
|
|
|||
|
Following are a few of the available ``oe-pkgdata-util`` subcommands.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
You can use the standard \* and ? globbing wildcards as part of
|
|||
|
package names and paths.
|
|||
|
|
|||
|
- ``oe-pkgdata-util list-pkgs [pattern]``: Lists all packages
|
|||
|
that have been built, optionally limiting the match to packages that
|
|||
|
match pattern.
|
|||
|
|
|||
|
- ``oe-pkgdata-util list-pkg-files package ...``: Lists the
|
|||
|
files and directories contained in the given packages.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
A different way to view the contents of a package is to look at
|
|||
|
the
|
|||
|
``${``\ :term:`WORKDIR`\ ``}/packages-split``
|
|||
|
directory of the recipe that generates the package. This directory
|
|||
|
is created by the
|
|||
|
:ref:`ref-tasks-package` task
|
|||
|
and has one subdirectory for each package the recipe generates,
|
|||
|
which contains the files stored in that package.
|
|||
|
|
|||
|
If you want to inspect the ``${WORKDIR}/packages-split``
|
|||
|
directory, make sure that :ref:`ref-classes-rm-work` is not
|
|||
|
enabled when you build the recipe.
|
|||
|
|
|||
|
- ``oe-pkgdata-util find-path path ...``: Lists the names of
|
|||
|
the packages that contain the given paths. For example, the following
|
|||
|
tells us that ``/usr/share/man/man1/make.1`` is contained in the
|
|||
|
``make-doc`` package::
|
|||
|
|
|||
|
$ oe-pkgdata-util find-path /usr/share/man/man1/make.1
|
|||
|
make-doc: /usr/share/man/man1/make.1
|
|||
|
|
|||
|
- ``oe-pkgdata-util lookup-recipe package ...``: Lists the name
|
|||
|
of the recipes that produce the given packages.
|
|||
|
|
|||
|
For more information on the ``oe-pkgdata-util`` command, use the help
|
|||
|
facility::
|
|||
|
|
|||
|
$ oe-pkgdata-util --help
|
|||
|
$ oe-pkgdata-util subcommand --help
|
|||
|
|
|||
|
Viewing Dependencies Between Recipes and Tasks
|
|||
|
==============================================
|
|||
|
|
|||
|
Sometimes it can be hard to see why BitBake wants to build other recipes
|
|||
|
before the one you have specified. Dependency information can help you
|
|||
|
understand why a recipe is built.
|
|||
|
|
|||
|
To generate dependency information for a recipe, run the following
|
|||
|
command::
|
|||
|
|
|||
|
$ bitbake -g recipename
|
|||
|
|
|||
|
This command writes the following files in the current directory:
|
|||
|
|
|||
|
- ``pn-buildlist``: A list of recipes/targets involved in building
|
|||
|
`recipename`. "Involved" here means that at least one task from the
|
|||
|
recipe needs to run when building `recipename` from scratch. Targets
|
|||
|
that are in
|
|||
|
:term:`ASSUME_PROVIDED`
|
|||
|
are not listed.
|
|||
|
|
|||
|
- ``task-depends.dot``: A graph showing dependencies between tasks.
|
|||
|
|
|||
|
The graphs are in :wikipedia:`DOT <DOT_%28graph_description_language%29>`
|
|||
|
format and can be converted to images (e.g. using the ``dot`` tool from
|
|||
|
`Graphviz <https://www.graphviz.org/>`__).
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
- DOT files use a plain text format. The graphs generated using the
|
|||
|
``bitbake -g`` command are often so large as to be difficult to
|
|||
|
read without special pruning (e.g. with BitBake's ``-I`` option)
|
|||
|
and processing. Despite the form and size of the graphs, the
|
|||
|
corresponding ``.dot`` files can still be possible to read and
|
|||
|
provide useful information.
|
|||
|
|
|||
|
As an example, the ``task-depends.dot`` file contains lines such
|
|||
|
as the following::
|
|||
|
|
|||
|
"libxslt.do_configure" -> "libxml2.do_populate_sysroot"
|
|||
|
|
|||
|
The above example line reveals that the
|
|||
|
:ref:`ref-tasks-configure`
|
|||
|
task in ``libxslt`` depends on the
|
|||
|
:ref:`ref-tasks-populate_sysroot`
|
|||
|
task in ``libxml2``, which is a normal
|
|||
|
:term:`DEPENDS` dependency
|
|||
|
between the two recipes.
|
|||
|
|
|||
|
- For an example of how ``.dot`` files can be processed, see the
|
|||
|
``scripts/contrib/graph-tool`` Python script, which finds and
|
|||
|
displays paths between graph nodes.
|
|||
|
|
|||
|
You can use a different method to view dependency information by using
|
|||
|
the following command::
|
|||
|
|
|||
|
$ bitbake -g -u taskexp recipename
|
|||
|
|
|||
|
This command
|
|||
|
displays a GUI window from which you can view build-time and runtime
|
|||
|
dependencies for the recipes involved in building recipename.
|
|||
|
|
|||
|
Viewing Task Variable Dependencies
|
|||
|
==================================
|
|||
|
|
|||
|
As mentioned in the
|
|||
|
":ref:`bitbake-user-manual/bitbake-user-manual-execution:checksums (signatures)`"
|
|||
|
section of the BitBake User Manual, BitBake tries to automatically determine
|
|||
|
what variables a task depends on so that it can rerun the task if any values of
|
|||
|
the variables change. This determination is usually reliable. However, if you
|
|||
|
do things like construct variable names at runtime, then you might have to
|
|||
|
manually declare dependencies on those variables using ``vardeps`` as described
|
|||
|
in the ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:variable flags`"
|
|||
|
section of the BitBake User Manual.
|
|||
|
|
|||
|
If you are unsure whether a variable dependency is being picked up
|
|||
|
automatically for a given task, you can list the variable dependencies
|
|||
|
BitBake has determined by doing the following:
|
|||
|
|
|||
|
#. Build the recipe containing the task::
|
|||
|
|
|||
|
$ bitbake recipename
|
|||
|
|
|||
|
#. Inside the :term:`STAMPS_DIR`
|
|||
|
directory, find the signature data (``sigdata``) file that
|
|||
|
corresponds to the task. The ``sigdata`` files contain a pickled
|
|||
|
Python database of all the metadata that went into creating the input
|
|||
|
checksum for the task. As an example, for the
|
|||
|
:ref:`ref-tasks-fetch` task of the
|
|||
|
``db`` recipe, the ``sigdata`` file might be found in the following
|
|||
|
location::
|
|||
|
|
|||
|
${BUILDDIR}/tmp/stamps/i586-poky-linux/db/6.0.30-r1.do_fetch.sigdata.7c048c18222b16ff0bcee2000ef648b1
|
|||
|
|
|||
|
For tasks that are accelerated through the shared state
|
|||
|
(:ref:`sstate <overview-manual/concepts:shared state cache>`) cache, an
|
|||
|
additional ``siginfo`` file is written into
|
|||
|
:term:`SSTATE_DIR` along with
|
|||
|
the cached task output. The ``siginfo`` files contain exactly the
|
|||
|
same information as ``sigdata`` files.
|
|||
|
|
|||
|
#. Run ``bitbake-dumpsig`` on the ``sigdata`` or ``siginfo`` file. Here
|
|||
|
is an example::
|
|||
|
|
|||
|
$ bitbake-dumpsig ${BUILDDIR}/tmp/stamps/i586-poky-linux/db/6.0.30-r1.do_fetch.sigdata.7c048c18222b16ff0bcee2000ef648b1
|
|||
|
|
|||
|
In the output of the above command, you will find a line like the
|
|||
|
following, which lists all the (inferred) variable dependencies for
|
|||
|
the task. This list also includes indirect dependencies from
|
|||
|
variables depending on other variables, recursively::
|
|||
|
|
|||
|
Task dependencies: ['PV', 'SRCREV', 'SRC_URI', 'SRC_URI[md5sum]', 'SRC_URI[sha256sum]', 'base_do_fetch']
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Functions (e.g. ``base_do_fetch``) also count as variable dependencies.
|
|||
|
These functions in turn depend on the variables they reference.
|
|||
|
|
|||
|
The output of ``bitbake-dumpsig`` also includes the value each
|
|||
|
variable had, a list of dependencies for each variable, and
|
|||
|
:term:`BB_BASEHASH_IGNORE_VARS`
|
|||
|
information.
|
|||
|
|
|||
|
There is also a ``bitbake-diffsigs`` command for comparing two
|
|||
|
``siginfo`` or ``sigdata`` files. This command can be helpful when
|
|||
|
trying to figure out what changed between two versions of a task. If you
|
|||
|
call ``bitbake-diffsigs`` with just one file, the command behaves like
|
|||
|
``bitbake-dumpsig``.
|
|||
|
|
|||
|
You can also use BitBake to dump out the signature construction
|
|||
|
information without executing tasks by using either of the following
|
|||
|
BitBake command-line options::
|
|||
|
|
|||
|
‐‐dump-signatures=SIGNATURE_HANDLER
|
|||
|
-S SIGNATURE_HANDLER
|
|||
|
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Two common values for `SIGNATURE_HANDLER` are "none" and "printdiff", which
|
|||
|
dump only the signature or compare the dumped signature with the cached one,
|
|||
|
respectively.
|
|||
|
|
|||
|
Using BitBake with either of these options causes BitBake to dump out
|
|||
|
``sigdata`` files in the ``stamps`` directory for every task it would
|
|||
|
have executed instead of building the specified target package.
|
|||
|
|
|||
|
Viewing Metadata Used to Create the Input Signature of a Shared State Task
|
|||
|
==========================================================================
|
|||
|
|
|||
|
Seeing what metadata went into creating the input signature of a shared
|
|||
|
state (sstate) task can be a useful debugging aid. This information is
|
|||
|
available in signature information (``siginfo``) files in
|
|||
|
:term:`SSTATE_DIR`. For
|
|||
|
information on how to view and interpret information in ``siginfo``
|
|||
|
files, see the
|
|||
|
":ref:`dev-manual/debugging:viewing task variable dependencies`" section.
|
|||
|
|
|||
|
For conceptual information on shared state, see the
|
|||
|
":ref:`overview-manual/concepts:shared state`"
|
|||
|
section in the Yocto Project Overview and Concepts Manual.
|
|||
|
|
|||
|
Invalidating Shared State to Force a Task to Run
|
|||
|
================================================
|
|||
|
|
|||
|
The OpenEmbedded build system uses
|
|||
|
:ref:`checksums <overview-manual/concepts:checksums (signatures)>` and
|
|||
|
:ref:`overview-manual/concepts:shared state` cache to avoid unnecessarily
|
|||
|
rebuilding tasks. Collectively, this scheme is known as "shared state
|
|||
|
code".
|
|||
|
|
|||
|
As with all schemes, this one has some drawbacks. It is possible that
|
|||
|
you could make implicit changes to your code that the checksum
|
|||
|
calculations do not take into account. These implicit changes affect a
|
|||
|
task's output but do not trigger the shared state code into rebuilding a
|
|||
|
recipe. Consider an example during which a tool changes its output.
|
|||
|
Assume that the output of ``rpmdeps`` changes. The result of the change
|
|||
|
should be that all the ``package`` and ``package_write_rpm`` shared
|
|||
|
state cache items become invalid. However, because the change to the
|
|||
|
output is external to the code and therefore implicit, the associated
|
|||
|
shared state cache items do not become invalidated. In this case, the
|
|||
|
build process uses the cached items rather than running the task again.
|
|||
|
Obviously, these types of implicit changes can cause problems.
|
|||
|
|
|||
|
To avoid these problems during the build, you need to understand the
|
|||
|
effects of any changes you make. Realize that changes you make directly
|
|||
|
to a function are automatically factored into the checksum calculation.
|
|||
|
Thus, these explicit changes invalidate the associated area of shared
|
|||
|
state cache. However, you need to be aware of any implicit changes that
|
|||
|
are not obvious changes to the code and could affect the output of a
|
|||
|
given task.
|
|||
|
|
|||
|
When you identify an implicit change, you can easily take steps to
|
|||
|
invalidate the cache and force the tasks to run. The steps you can take
|
|||
|
are as simple as changing a function's comments in the source code. For
|
|||
|
example, to invalidate package shared state files, change the comment
|
|||
|
statements of
|
|||
|
:ref:`ref-tasks-package` or the
|
|||
|
comments of one of the functions it calls. Even though the change is
|
|||
|
purely cosmetic, it causes the checksum to be recalculated and forces
|
|||
|
the build system to run the task again.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
For an example of a commit that makes a cosmetic change to invalidate
|
|||
|
shared state, see this
|
|||
|
:yocto_git:`commit </poky/commit/meta/classes/package.bbclass?id=737f8bbb4f27b4837047cb9b4fbfe01dfde36d54>`.
|
|||
|
|
|||
|
Running Specific Tasks
|
|||
|
======================
|
|||
|
|
|||
|
Any given recipe consists of a set of tasks. The standard BitBake
|
|||
|
behavior in most cases is: :ref:`ref-tasks-fetch`, :ref:`ref-tasks-unpack`, :ref:`ref-tasks-patch`,
|
|||
|
:ref:`ref-tasks-configure`, :ref:`ref-tasks-compile`, :ref:`ref-tasks-install`, :ref:`ref-tasks-package`,
|
|||
|
:ref:`do_package_write_* <ref-tasks-package_write_deb>`, and :ref:`ref-tasks-build`. The default task is
|
|||
|
:ref:`ref-tasks-build` and any tasks on which it depends build first. Some tasks,
|
|||
|
such as :ref:`ref-tasks-devshell`, are not part of the default build chain. If you
|
|||
|
wish to run a task that is not part of the default build chain, you can
|
|||
|
use the ``-c`` option in BitBake. Here is an example::
|
|||
|
|
|||
|
$ bitbake matchbox-desktop -c devshell
|
|||
|
|
|||
|
The ``-c`` option respects task dependencies, which means that all other
|
|||
|
tasks (including tasks from other recipes) that the specified task
|
|||
|
depends on will be run before the task. Even when you manually specify a
|
|||
|
task to run with ``-c``, BitBake will only run the task if it considers
|
|||
|
it "out of date". See the
|
|||
|
":ref:`overview-manual/concepts:stamp files and the rerunning of tasks`"
|
|||
|
section in the Yocto Project Overview and Concepts Manual for how
|
|||
|
BitBake determines whether a task is "out of date".
|
|||
|
|
|||
|
If you want to force an up-to-date task to be rerun (e.g. because you
|
|||
|
made manual modifications to the recipe's
|
|||
|
:term:`WORKDIR` that you want to try
|
|||
|
out), then you can use the ``-f`` option.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
The reason ``-f`` is never required when running the
|
|||
|
:ref:`ref-tasks-devshell` task is because the
|
|||
|
[\ :ref:`nostamp <bitbake-user-manual/bitbake-user-manual-metadata:variable flags>`\ ]
|
|||
|
variable flag is already set for the task.
|
|||
|
|
|||
|
The following example shows one way you can use the ``-f`` option::
|
|||
|
|
|||
|
$ bitbake matchbox-desktop
|
|||
|
.
|
|||
|
.
|
|||
|
make some changes to the source code in the work directory
|
|||
|
.
|
|||
|
.
|
|||
|
$ bitbake matchbox-desktop -c compile -f
|
|||
|
$ bitbake matchbox-desktop
|
|||
|
|
|||
|
This sequence first builds and then recompiles ``matchbox-desktop``. The
|
|||
|
last command reruns all tasks (basically the packaging tasks) after the
|
|||
|
compile. BitBake recognizes that the :ref:`ref-tasks-compile` task was rerun and
|
|||
|
therefore understands that the other tasks also need to be run again.
|
|||
|
|
|||
|
Another, shorter way to rerun a task and all
|
|||
|
:ref:`ref-manual/tasks:normal recipe build tasks`
|
|||
|
that depend on it is to use the ``-C`` option.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
This option is upper-cased and is separate from the ``-c``
|
|||
|
option, which is lower-cased.
|
|||
|
|
|||
|
Using this option invalidates the given task and then runs the
|
|||
|
:ref:`ref-tasks-build` task, which is
|
|||
|
the default task if no task is given, and the tasks on which it depends.
|
|||
|
You could replace the final two commands in the previous example with
|
|||
|
the following single command::
|
|||
|
|
|||
|
$ bitbake matchbox-desktop -C compile
|
|||
|
|
|||
|
Internally, the ``-f`` and ``-C`` options work by tainting (modifying)
|
|||
|
the input checksum of the specified task. This tainting indirectly
|
|||
|
causes the task and its dependent tasks to be rerun through the normal
|
|||
|
task dependency mechanisms.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
BitBake explicitly keeps track of which tasks have been tainted in
|
|||
|
this fashion, and will print warnings such as the following for
|
|||
|
builds involving such tasks:
|
|||
|
|
|||
|
.. code-block:: none
|
|||
|
|
|||
|
WARNING: /home/ulf/poky/meta/recipes-sato/matchbox-desktop/matchbox-desktop_2.1.bb.do_compile is tainted from a forced run
|
|||
|
|
|||
|
|
|||
|
The purpose of the warning is to let you know that the work directory
|
|||
|
and build output might not be in the clean state they would be in for
|
|||
|
a "normal" build, depending on what actions you took. To get rid of
|
|||
|
such warnings, you can remove the work directory and rebuild the
|
|||
|
recipe, as follows::
|
|||
|
|
|||
|
$ bitbake matchbox-desktop -c clean
|
|||
|
$ bitbake matchbox-desktop
|
|||
|
|
|||
|
|
|||
|
You can view a list of tasks in a given package by running the
|
|||
|
:ref:`ref-tasks-listtasks` task as follows::
|
|||
|
|
|||
|
$ bitbake matchbox-desktop -c listtasks
|
|||
|
|
|||
|
The results appear as output to the console and are also in
|
|||
|
the file ``${WORKDIR}/temp/log.do_listtasks``.
|
|||
|
|
|||
|
General BitBake Problems
|
|||
|
========================
|
|||
|
|
|||
|
You can see debug output from BitBake by using the ``-D`` option. The
|
|||
|
debug output gives more information about what BitBake is doing and the
|
|||
|
reason behind it. Each ``-D`` option you use increases the logging
|
|||
|
level. The most common usage is ``-DDD``.
|
|||
|
|
|||
|
The output from ``bitbake -DDD -v targetname`` can reveal why BitBake
|
|||
|
chose a certain version of a package or why BitBake picked a certain
|
|||
|
provider. This command could also help you in a situation where you
|
|||
|
think BitBake did something unexpected.
|
|||
|
|
|||
|
Building with No Dependencies
|
|||
|
=============================
|
|||
|
|
|||
|
To build a specific recipe (``.bb`` file), you can use the following
|
|||
|
command form::
|
|||
|
|
|||
|
$ bitbake -b somepath/somerecipe.bb
|
|||
|
|
|||
|
This command form does
|
|||
|
not check for dependencies. Consequently, you should use it only when
|
|||
|
you know existing dependencies have been met.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
You can also specify fragments of the filename. In this case, BitBake
|
|||
|
checks for a unique match.
|
|||
|
|
|||
|
Recipe Logging Mechanisms
|
|||
|
=========================
|
|||
|
|
|||
|
The Yocto Project provides several logging functions for producing
|
|||
|
debugging output and reporting errors and warnings. For Python
|
|||
|
functions, the following logging functions are available. All of these functions
|
|||
|
log to ``${T}/log.do_``\ `task`, and can also log to standard output
|
|||
|
(stdout) with the right settings:
|
|||
|
|
|||
|
- ``bb.plain(msg)``: Writes msg as is to the log while also
|
|||
|
logging to stdout.
|
|||
|
|
|||
|
- ``bb.note(msg)``: Writes "NOTE: msg" to the log. Also logs to
|
|||
|
stdout if BitBake is called with "-v".
|
|||
|
|
|||
|
- ``bb.debug(level, msg)``: Writes "DEBUG: msg" to the log. Also logs to
|
|||
|
stdout if the log level is greater than or equal to level. See the
|
|||
|
":ref:`bitbake-user-manual/bitbake-user-manual-intro:usage and syntax`"
|
|||
|
option in the BitBake User Manual for more information.
|
|||
|
|
|||
|
- ``bb.warn(msg)``: Writes "WARNING: msg" to the log while also
|
|||
|
logging to stdout.
|
|||
|
|
|||
|
- ``bb.error(msg)``: Writes "ERROR: msg" to the log while also
|
|||
|
logging to standard out (stdout).
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Calling this function does not cause the task to fail.
|
|||
|
|
|||
|
- ``bb.fatal(msg)``: This logging function is similar to
|
|||
|
``bb.error(msg)`` but also causes the calling task to fail.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
``bb.fatal()`` raises an exception, which means you do not need to put a
|
|||
|
"return" statement after the function.
|
|||
|
|
|||
|
The same logging functions are also available in shell functions, under
|
|||
|
the names ``bbplain``, ``bbnote``, ``bbdebug``, ``bbwarn``, ``bberror``,
|
|||
|
and ``bbfatal``. The :ref:`ref-classes-logging` class
|
|||
|
implements these functions. See that class in the ``meta/classes``
|
|||
|
folder of the :term:`Source Directory` for information.
|
|||
|
|
|||
|
Logging With Python
|
|||
|
-------------------
|
|||
|
|
|||
|
When creating recipes using Python and inserting code that handles build
|
|||
|
logs, keep in mind the goal is to have informative logs while keeping
|
|||
|
the console as "silent" as possible. Also, if you want status messages
|
|||
|
in the log, use the "debug" loglevel.
|
|||
|
|
|||
|
Following is an example written in Python. The code handles logging for
|
|||
|
a function that determines the number of tasks needed to be run. See the
|
|||
|
":ref:`ref-tasks-listtasks`"
|
|||
|
section for additional information::
|
|||
|
|
|||
|
python do_listtasks() {
|
|||
|
bb.debug(2, "Starting to figure out the task list")
|
|||
|
if noteworthy_condition:
|
|||
|
bb.note("There are 47 tasks to run")
|
|||
|
bb.debug(2, "Got to point xyz")
|
|||
|
if warning_trigger:
|
|||
|
bb.warn("Detected warning_trigger, this might be a problem later.")
|
|||
|
if recoverable_error:
|
|||
|
bb.error("Hit recoverable_error, you really need to fix this!")
|
|||
|
if fatal_error:
|
|||
|
bb.fatal("fatal_error detected, unable to print the task list")
|
|||
|
bb.plain("The tasks present are abc")
|
|||
|
bb.debug(2, "Finished figuring out the tasklist")
|
|||
|
}
|
|||
|
|
|||
|
Logging With Bash
|
|||
|
-----------------
|
|||
|
|
|||
|
When creating recipes using Bash and inserting code that handles build
|
|||
|
logs, you have the same goals --- informative with minimal console output.
|
|||
|
The syntax you use for recipes written in Bash is similar to that of
|
|||
|
recipes written in Python described in the previous section.
|
|||
|
|
|||
|
Following is an example written in Bash. The code logs the progress of
|
|||
|
the ``do_my_function`` function::
|
|||
|
|
|||
|
do_my_function() {
|
|||
|
bbdebug 2 "Running do_my_function"
|
|||
|
if [ exceptional_condition ]; then
|
|||
|
bbnote "Hit exceptional_condition"
|
|||
|
fi
|
|||
|
bbdebug 2 "Got to point xyz"
|
|||
|
if [ warning_trigger ]; then
|
|||
|
bbwarn "Detected warning_trigger, this might cause a problem later."
|
|||
|
fi
|
|||
|
if [ recoverable_error ]; then
|
|||
|
bberror "Hit recoverable_error, correcting"
|
|||
|
fi
|
|||
|
if [ fatal_error ]; then
|
|||
|
bbfatal "fatal_error detected"
|
|||
|
fi
|
|||
|
bbdebug 2 "Completed do_my_function"
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Debugging Parallel Make Races
|
|||
|
=============================
|
|||
|
|
|||
|
A parallel ``make`` race occurs when the build consists of several parts
|
|||
|
that are run simultaneously and a situation occurs when the output or
|
|||
|
result of one part is not ready for use with a different part of the
|
|||
|
build that depends on that output. Parallel make races are annoying and
|
|||
|
can sometimes be difficult to reproduce and fix. However, there are some simple
|
|||
|
tips and tricks that can help you debug and fix them. This section
|
|||
|
presents a real-world example of an error encountered on the Yocto
|
|||
|
Project autobuilder and the process used to fix it.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
If you cannot properly fix a ``make`` race condition, you can work around it
|
|||
|
by clearing either the :term:`PARALLEL_MAKE` or :term:`PARALLEL_MAKEINST`
|
|||
|
variables.
|
|||
|
|
|||
|
The Failure
|
|||
|
-----------
|
|||
|
|
|||
|
For this example, assume that you are building an image that depends on
|
|||
|
the "neard" package. And, during the build, BitBake runs into problems
|
|||
|
and creates the following output.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
This example log file has longer lines artificially broken to make
|
|||
|
the listing easier to read.
|
|||
|
|
|||
|
If you examine the output or the log file, you see the failure during
|
|||
|
``make``:
|
|||
|
|
|||
|
.. code-block:: none
|
|||
|
|
|||
|
| DEBUG: SITE files ['endian-little', 'bit-32', 'ix86-common', 'common-linux', 'common-glibc', 'i586-linux', 'common']
|
|||
|
| DEBUG: Executing shell function do_compile
|
|||
|
| NOTE: make -j 16
|
|||
|
| make --no-print-directory all-am
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/types.h include/near/types.h
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/log.h include/near/log.h
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/plugin.h include/near/plugin.h
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/tag.h include/near/tag.h
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/adapter.h include/near/adapter.h
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/ndef.h include/near/ndef.h
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/tlv.h include/near/tlv.h
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/setting.h include/near/setting.h
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| /bin/mkdir -p include/near
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/device.h include/near/device.h
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/nfc_copy.h include/near/nfc_copy.h
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/snep.h include/near/snep.h
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/version.h include/near/version.h
|
|||
|
| ln -s /home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/work/i586-poky-linux/neard/
|
|||
|
0.14-r0/neard-0.14/include/dbus.h include/near/dbus.h
|
|||
|
| ./src/genbuiltin nfctype1 nfctype2 nfctype3 nfctype4 p2p > src/builtin.h
|
|||
|
| i586-poky-linux-gcc -m32 -march=i586 --sysroot=/home/pokybuild/yocto-autobuilder/nightly-x86/
|
|||
|
build/build/tmp/sysroots/qemux86 -DHAVE_CONFIG_H -I. -I./include -I./src -I./gdbus -I/home/pokybuild/
|
|||
|
yocto-autobuilder/nightly-x86/build/build/tmp/sysroots/qemux86/usr/include/glib-2.0
|
|||
|
-I/home/pokybuild/yocto-autobuilder/nightly-x86/build/build/tmp/sysroots/qemux86/usr/
|
|||
|
lib/glib-2.0/include -I/home/pokybuild/yocto-autobuilder/nightly-x86/build/build/
|
|||
|
tmp/sysroots/qemux86/usr/include/dbus-1.0 -I/home/pokybuild/yocto-autobuilder/
|
|||
|
nightly-x86/build/build/tmp/sysroots/qemux86/usr/lib/dbus-1.0/include -I/home/pokybuild/yocto-autobuilder/
|
|||
|
nightly-x86/build/build/tmp/sysroots/qemux86/usr/include/libnl3
|
|||
|
-DNEAR_PLUGIN_BUILTIN -DPLUGINDIR=\""/usr/lib/near/plugins"\"
|
|||
|
-DCONFIGDIR=\""/etc/neard\"" -O2 -pipe -g -feliminate-unused-debug-types -c
|
|||
|
-o tools/snep-send.o tools/snep-send.c
|
|||
|
| In file included from tools/snep-send.c:16:0:
|
|||
|
| tools/../src/near.h:41:23: fatal error: near/dbus.h: No such file or directory
|
|||
|
| #include <near/dbus.h>
|
|||
|
| ^
|
|||
|
| compilation terminated.
|
|||
|
| make[1]: *** [tools/snep-send.o] Error 1
|
|||
|
| make[1]: *** Waiting for unfinished jobs....
|
|||
|
| make: *** [all] Error 2
|
|||
|
| ERROR: oe_runmake failed
|
|||
|
|
|||
|
Reproducing the Error
|
|||
|
---------------------
|
|||
|
|
|||
|
Because race conditions are intermittent, they do not manifest
|
|||
|
themselves every time you do the build. In fact, most times the build
|
|||
|
will complete without problems even though the potential race condition
|
|||
|
exists. Thus, once the error surfaces, you need a way to reproduce it.
|
|||
|
|
|||
|
In this example, compiling the "neard" package is causing the problem.
|
|||
|
So the first thing to do is build "neard" locally. Before you start the
|
|||
|
build, set the
|
|||
|
:term:`PARALLEL_MAKE` variable
|
|||
|
in your ``local.conf`` file to a high number (e.g. "-j 20"). Using a
|
|||
|
high value for :term:`PARALLEL_MAKE` increases the chances of the race
|
|||
|
condition showing up::
|
|||
|
|
|||
|
$ bitbake neard
|
|||
|
|
|||
|
Once the local build for "neard" completes, start a ``devshell`` build::
|
|||
|
|
|||
|
$ bitbake neard -c devshell
|
|||
|
|
|||
|
For information on how to use a ``devshell``, see the
|
|||
|
":ref:`dev-manual/development-shell:using a development shell`" section.
|
|||
|
|
|||
|
In the ``devshell``, do the following::
|
|||
|
|
|||
|
$ make clean
|
|||
|
$ make tools/snep-send.o
|
|||
|
|
|||
|
The ``devshell`` commands cause the failure to clearly
|
|||
|
be visible. In this case, there is a missing dependency for the ``neard``
|
|||
|
Makefile target. Here is some abbreviated, sample output with the
|
|||
|
missing dependency clearly visible at the end::
|
|||
|
|
|||
|
i586-poky-linux-gcc -m32 -march=i586 --sysroot=/home/scott-lenovo/......
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
tools/snep-send.c
|
|||
|
In file included from tools/snep-send.c:16:0:
|
|||
|
tools/../src/near.h:41:23: fatal error: near/dbus.h: No such file or directory
|
|||
|
#include <near/dbus.h>
|
|||
|
^
|
|||
|
compilation terminated.
|
|||
|
make: *** [tools/snep-send.o] Error 1
|
|||
|
$
|
|||
|
|
|||
|
|
|||
|
Creating a Patch for the Fix
|
|||
|
----------------------------
|
|||
|
|
|||
|
Because there is a missing dependency for the Makefile target, you need
|
|||
|
to patch the ``Makefile.am`` file, which is generated from
|
|||
|
``Makefile.in``. You can use Quilt to create the patch::
|
|||
|
|
|||
|
$ quilt new parallelmake.patch
|
|||
|
Patch patches/parallelmake.patch is now on top
|
|||
|
$ quilt add Makefile.am
|
|||
|
File Makefile.am added to patch patches/parallelmake.patch
|
|||
|
|
|||
|
For more information on using Quilt, see the
|
|||
|
":ref:`dev-manual/quilt:using quilt in your workflow`" section.
|
|||
|
|
|||
|
At this point you need to make the edits to ``Makefile.am`` to add the
|
|||
|
missing dependency. For our example, you have to add the following line
|
|||
|
to the file::
|
|||
|
|
|||
|
tools/snep-send.$(OBJEXT): include/near/dbus.h
|
|||
|
|
|||
|
Once you have edited the file, use the ``refresh`` command to create the
|
|||
|
patch::
|
|||
|
|
|||
|
$ quilt refresh
|
|||
|
Refreshed patch patches/parallelmake.patch
|
|||
|
|
|||
|
Once the patch file is created, you need to add it back to the originating
|
|||
|
recipe folder. Here is an example assuming a top-level
|
|||
|
:term:`Source Directory` named ``poky``::
|
|||
|
|
|||
|
$ cp patches/parallelmake.patch poky/meta/recipes-connectivity/neard/neard
|
|||
|
|
|||
|
The final thing you need to do to implement the fix in the build is to
|
|||
|
update the "neard" recipe (i.e. ``neard-0.14.bb``) so that the
|
|||
|
:term:`SRC_URI` statement includes
|
|||
|
the patch file. The recipe file is in the folder above the patch. Here
|
|||
|
is what the edited :term:`SRC_URI` statement would look like::
|
|||
|
|
|||
|
SRC_URI = "${KERNELORG_MIRROR}/linux/network/nfc/${BPN}-${PV}.tar.xz \
|
|||
|
file://neard.in \
|
|||
|
file://neard.service.in \
|
|||
|
file://parallelmake.patch \
|
|||
|
"
|
|||
|
|
|||
|
With the patch complete and moved to the correct folder and the
|
|||
|
:term:`SRC_URI` statement updated, you can exit the ``devshell``::
|
|||
|
|
|||
|
$ exit
|
|||
|
|
|||
|
Testing the Build
|
|||
|
-----------------
|
|||
|
|
|||
|
With everything in place, you can get back to trying the build again
|
|||
|
locally::
|
|||
|
|
|||
|
$ bitbake neard
|
|||
|
|
|||
|
This build should succeed.
|
|||
|
|
|||
|
Now you can open up a ``devshell`` again and repeat the clean and make
|
|||
|
operations as follows::
|
|||
|
|
|||
|
$ bitbake neard -c devshell
|
|||
|
$ make clean
|
|||
|
$ make tools/snep-send.o
|
|||
|
|
|||
|
The build should work without issue.
|
|||
|
|
|||
|
As with all solved problems, if they originated upstream, you need to
|
|||
|
submit the fix for the recipe in OE-Core and upstream so that the
|
|||
|
problem is taken care of at its source. See the
|
|||
|
":doc:`../contributor-guide/submit-changes`" section for more information.
|
|||
|
|
|||
|
Debugging With the GNU Project Debugger (GDB) Remotely
|
|||
|
======================================================
|
|||
|
|
|||
|
GDB allows you to examine running programs, which in turn helps you to
|
|||
|
understand and fix problems. It also allows you to perform post-mortem
|
|||
|
style analysis of program crashes. GDB is available as a package within
|
|||
|
the Yocto Project and is installed in SDK images by default. See the
|
|||
|
":ref:`ref-manual/images:Images`" chapter in the Yocto
|
|||
|
Project Reference Manual for a description of these images. You can find
|
|||
|
information on GDB at https://sourceware.org/gdb/.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
For best results, install debug (``-dbg``) packages for the applications you
|
|||
|
are going to debug. Doing so makes extra debug symbols available that give
|
|||
|
you more meaningful output.
|
|||
|
|
|||
|
Sometimes, due to memory or disk space constraints, it is not possible
|
|||
|
to use GDB directly on the remote target to debug applications. These
|
|||
|
constraints arise because GDB needs to load the debugging information
|
|||
|
and the binaries of the process being debugged. Additionally, GDB needs
|
|||
|
to perform many computations to locate information such as function
|
|||
|
names, variable names and values, stack traces and so forth --- even
|
|||
|
before starting the debugging process. These extra computations place
|
|||
|
more load on the target system and can alter the characteristics of the
|
|||
|
program being debugged.
|
|||
|
|
|||
|
To help get past the previously mentioned constraints, there are two
|
|||
|
methods you can use: running a debuginfod server and using gdbserver.
|
|||
|
|
|||
|
Using the debuginfod server method
|
|||
|
----------------------------------
|
|||
|
|
|||
|
``debuginfod`` from ``elfutils`` is a way to distribute ``debuginfo`` files.
|
|||
|
Running a ``debuginfod`` server makes debug symbols readily available,
|
|||
|
which means you don't need to download debugging information
|
|||
|
and the binaries of the process being debugged. You can just fetch
|
|||
|
debug symbols from the server.
|
|||
|
|
|||
|
To run a ``debuginfod`` server, you need to do the following:
|
|||
|
|
|||
|
- Ensure that ``debuginfod`` is present in :term:`DISTRO_FEATURES`
|
|||
|
(it already is in ``OpenEmbedded-core`` defaults and ``poky`` reference distribution).
|
|||
|
If not, set in your distro config file or in ``local.conf``::
|
|||
|
|
|||
|
DISTRO_FEATURES:append = " debuginfod"
|
|||
|
|
|||
|
This distro feature enables the server and client library in ``elfutils``,
|
|||
|
and enables ``debuginfod`` support in clients (at the moment, ``gdb`` and ``binutils``).
|
|||
|
|
|||
|
- Run the following commands to launch the ``debuginfod`` server on the host::
|
|||
|
|
|||
|
$ oe-debuginfod
|
|||
|
|
|||
|
- To use ``debuginfod`` on the target, you need to know the ip:port where
|
|||
|
``debuginfod`` is listening on the host (port defaults to 8002), and export
|
|||
|
that into the shell environment, for example in ``qemu``::
|
|||
|
|
|||
|
root@qemux86-64:~# export DEBUGINFOD_URLS="http://192.168.7.1:8002/"
|
|||
|
|
|||
|
- Then debug info fetching should simply work when running the target ``gdb``,
|
|||
|
``readelf`` or ``objdump``, for example::
|
|||
|
|
|||
|
root@qemux86-64:~# gdb /bin/cat
|
|||
|
...
|
|||
|
Reading symbols from /bin/cat...
|
|||
|
Downloading separate debug info for /bin/cat...
|
|||
|
Reading symbols from /home/root/.cache/debuginfod_client/923dc4780cfbc545850c616bffa884b6b5eaf322/debuginfo...
|
|||
|
|
|||
|
- It's also possible to use ``debuginfod-find`` to just query the server::
|
|||
|
|
|||
|
root@qemux86-64:~# debuginfod-find debuginfo /bin/ls
|
|||
|
/home/root/.cache/debuginfod_client/356edc585f7f82d46f94fcb87a86a3fe2d2e60bd/debuginfo
|
|||
|
|
|||
|
|
|||
|
Using the gdbserver method
|
|||
|
--------------------------
|
|||
|
|
|||
|
gdbserver, which runs on the remote target and does not load any
|
|||
|
debugging information from the debugged process. Instead, a GDB instance
|
|||
|
processes the debugging information that is run on a remote computer -
|
|||
|
the host GDB. The host GDB then sends control commands to gdbserver to
|
|||
|
make it stop or start the debugged program, as well as read or write
|
|||
|
memory regions of that debugged program. All the debugging information
|
|||
|
loaded and processed as well as all the heavy debugging is done by the
|
|||
|
host GDB. Offloading these processes gives the gdbserver running on the
|
|||
|
target a chance to remain small and fast.
|
|||
|
|
|||
|
Because the host GDB is responsible for loading the debugging
|
|||
|
information and for doing the necessary processing to make actual
|
|||
|
debugging happen, you have to make sure the host can access the
|
|||
|
unstripped binaries complete with their debugging information and also
|
|||
|
be sure the target is compiled with no optimizations. The host GDB must
|
|||
|
also have local access to all the libraries used by the debugged
|
|||
|
program. Because gdbserver does not need any local debugging
|
|||
|
information, the binaries on the remote target can remain stripped.
|
|||
|
However, the binaries must also be compiled without optimization so they
|
|||
|
match the host's binaries.
|
|||
|
|
|||
|
To remain consistent with GDB documentation and terminology, the binary
|
|||
|
being debugged on the remote target machine is referred to as the
|
|||
|
"inferior" binary. For documentation on GDB see the `GDB
|
|||
|
site <https://sourceware.org/gdb/documentation/>`__.
|
|||
|
|
|||
|
The following steps show you how to debug using the GNU project
|
|||
|
debugger.
|
|||
|
|
|||
|
#. *Configure your build system to construct the companion debug
|
|||
|
filesystem:*
|
|||
|
|
|||
|
In your ``local.conf`` file, set the following::
|
|||
|
|
|||
|
IMAGE_GEN_DEBUGFS = "1"
|
|||
|
IMAGE_FSTYPES_DEBUGFS = "tar.bz2"
|
|||
|
|
|||
|
These options cause the
|
|||
|
OpenEmbedded build system to generate a special companion filesystem
|
|||
|
fragment, which contains the matching source and debug symbols to
|
|||
|
your deployable filesystem. The build system does this by looking at
|
|||
|
what is in the deployed filesystem, and pulling the corresponding
|
|||
|
``-dbg`` packages.
|
|||
|
|
|||
|
The companion debug filesystem is not a complete filesystem, but only
|
|||
|
contains the debug fragments. This filesystem must be combined with
|
|||
|
the full filesystem for debugging. Subsequent steps in this procedure
|
|||
|
show how to combine the partial filesystem with the full filesystem.
|
|||
|
|
|||
|
#. *Configure the system to include gdbserver in the target filesystem:*
|
|||
|
|
|||
|
Make the following addition in your ``local.conf`` file::
|
|||
|
|
|||
|
EXTRA_IMAGE_FEATURES:append = " tools-debug"
|
|||
|
|
|||
|
The change makes
|
|||
|
sure the ``gdbserver`` package is included.
|
|||
|
|
|||
|
#. *Build the environment:*
|
|||
|
|
|||
|
Use the following command to construct the image and the companion
|
|||
|
Debug Filesystem::
|
|||
|
|
|||
|
$ bitbake image
|
|||
|
|
|||
|
Build the cross GDB component and
|
|||
|
make it available for debugging. Build the SDK that matches the
|
|||
|
image. Building the SDK is best for a production build that can be
|
|||
|
used later for debugging, especially during long term maintenance::
|
|||
|
|
|||
|
$ bitbake -c populate_sdk image
|
|||
|
|
|||
|
Alternatively, you can build the minimal toolchain components that
|
|||
|
match the target. Doing so creates a smaller than typical SDK and
|
|||
|
only contains a minimal set of components with which to build simple
|
|||
|
test applications, as well as run the debugger::
|
|||
|
|
|||
|
$ bitbake meta-toolchain
|
|||
|
|
|||
|
A final method is to build Gdb itself within the build system::
|
|||
|
|
|||
|
$ bitbake gdb-cross-<architecture>
|
|||
|
|
|||
|
Doing so produces a temporary copy of
|
|||
|
``cross-gdb`` you can use for debugging during development. While
|
|||
|
this is the quickest approach, the two previous methods in this step
|
|||
|
are better when considering long-term maintenance strategies.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
If you run ``bitbake gdb-cross``, the OpenEmbedded build system suggests
|
|||
|
the actual image (e.g. ``gdb-cross-i586``). The suggestion is usually the
|
|||
|
actual name you want to use.
|
|||
|
|
|||
|
#. *Set up the* ``debugfs``\ *:*
|
|||
|
|
|||
|
Run the following commands to set up the ``debugfs``::
|
|||
|
|
|||
|
$ mkdir debugfs
|
|||
|
$ cd debugfs
|
|||
|
$ tar xvfj build-dir/tmp/deploy/images/machine/image.rootfs.tar.bz2
|
|||
|
$ tar xvfj build-dir/tmp/deploy/images/machine/image-dbg.rootfs.tar.bz2
|
|||
|
|
|||
|
#. *Set up GDB:*
|
|||
|
|
|||
|
Install the SDK (if you built one) and then source the correct
|
|||
|
environment file. Sourcing the environment file puts the SDK in your
|
|||
|
``PATH`` environment variable and sets ``$GDB`` to the SDK's debugger.
|
|||
|
|
|||
|
If you are using the build system, Gdb is located in
|
|||
|
`build-dir`\ ``/tmp/sysroots/``\ `host`\ ``/usr/bin/``\ `architecture`\ ``/``\ `architecture`\ ``-gdb``
|
|||
|
|
|||
|
#. *Boot the target:*
|
|||
|
|
|||
|
For information on how to run QEMU, see the `QEMU
|
|||
|
Documentation <https://wiki.qemu.org/Documentation/GettingStartedDevelopers>`__.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Be sure to verify that your host can access the target via TCP.
|
|||
|
|
|||
|
#. *Debug a program:*
|
|||
|
|
|||
|
Debugging a program involves running gdbserver on the target and then
|
|||
|
running Gdb on the host. The example in this step debugs ``gzip``:
|
|||
|
|
|||
|
.. code-block:: shell
|
|||
|
|
|||
|
root@qemux86:~# gdbserver localhost:1234 /bin/gzip —help
|
|||
|
|
|||
|
For
|
|||
|
additional gdbserver options, see the `GDB Server
|
|||
|
Documentation <https://www.gnu.org/software/gdb/documentation/>`__.
|
|||
|
|
|||
|
After running gdbserver on the target, you need to run Gdb on the
|
|||
|
host and configure it and connect to the target. Use these commands::
|
|||
|
|
|||
|
$ cd directory-holding-the-debugfs-directory
|
|||
|
$ arch-gdb
|
|||
|
(gdb) set sysroot debugfs
|
|||
|
(gdb) set substitute-path /usr/src/debug debugfs/usr/src/debug
|
|||
|
(gdb) target remote IP-of-target:1234
|
|||
|
|
|||
|
At this
|
|||
|
point, everything should automatically load (i.e. matching binaries,
|
|||
|
symbols and headers).
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
The Gdb ``set`` commands in the previous example can be placed into the
|
|||
|
users ``~/.gdbinit`` file. Upon starting, Gdb automatically runs whatever
|
|||
|
commands are in that file.
|
|||
|
|
|||
|
#. *Deploying without a full image rebuild:*
|
|||
|
|
|||
|
In many cases, during development you want a quick method to deploy a
|
|||
|
new binary to the target and debug it, without waiting for a full
|
|||
|
image build.
|
|||
|
|
|||
|
One approach to solving this situation is to just build the component
|
|||
|
you want to debug. Once you have built the component, copy the
|
|||
|
executable directly to both the target and the host ``debugfs``.
|
|||
|
|
|||
|
If the binary is processed through the debug splitting in
|
|||
|
OpenEmbedded, you should also copy the debug items (i.e. ``.debug``
|
|||
|
contents and corresponding ``/usr/src/debug`` files) from the work
|
|||
|
directory. Here is an example::
|
|||
|
|
|||
|
$ bitbake bash
|
|||
|
$ bitbake -c devshell bash
|
|||
|
$ cd ..
|
|||
|
$ scp packages-split/bash/bin/bash target:/bin/bash
|
|||
|
$ cp -a packages-split/bash-dbg/\* path/debugfs
|
|||
|
|
|||
|
Debugging with the GNU Project Debugger (GDB) on the Target
|
|||
|
===========================================================
|
|||
|
|
|||
|
The previous section addressed using GDB remotely for debugging
|
|||
|
purposes, which is the most usual case due to the inherent hardware
|
|||
|
limitations on many embedded devices. However, debugging in the target
|
|||
|
hardware itself is also possible with more powerful devices. This
|
|||
|
section describes what you need to do in order to support using GDB to
|
|||
|
debug on the target hardware.
|
|||
|
|
|||
|
To support this kind of debugging, you need do the following:
|
|||
|
|
|||
|
- Ensure that GDB is on the target. You can do this by making
|
|||
|
the following addition to your ``local.conf`` file::
|
|||
|
|
|||
|
EXTRA_IMAGE_FEATURES:append = " tools-debug"
|
|||
|
|
|||
|
- Ensure that debug symbols are present. You can do so by adding the
|
|||
|
corresponding ``-dbg`` package to :term:`IMAGE_INSTALL`::
|
|||
|
|
|||
|
IMAGE_INSTALL:append = " packagename-dbg"
|
|||
|
|
|||
|
Alternatively, you can add the following to ``local.conf`` to include
|
|||
|
all the debug symbols::
|
|||
|
|
|||
|
EXTRA_IMAGE_FEATURES:append = " dbg-pkgs"
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
To improve the debug information accuracy, you can reduce the level
|
|||
|
of optimization used by the compiler. For example, when adding the
|
|||
|
following line to your ``local.conf`` file, you will reduce optimization
|
|||
|
from :term:`FULL_OPTIMIZATION` of "-O2" to :term:`DEBUG_OPTIMIZATION`
|
|||
|
of "-O -fno-omit-frame-pointer"::
|
|||
|
|
|||
|
DEBUG_BUILD = "1"
|
|||
|
|
|||
|
Consider that this will reduce the application's performance and is
|
|||
|
recommended only for debugging purposes.
|
|||
|
|
|||
|
Other Debugging Tips
|
|||
|
====================
|
|||
|
|
|||
|
Here are some other tips that you might find useful:
|
|||
|
|
|||
|
- When adding new packages, it is worth watching for undesirable items
|
|||
|
making their way into compiler command lines. For example, you do not
|
|||
|
want references to local system files like ``/usr/lib/`` or
|
|||
|
``/usr/include/``.
|
|||
|
|
|||
|
- If you want to remove the ``psplash`` boot splashscreen, add
|
|||
|
``psplash=false`` to the kernel command line. Doing so prevents
|
|||
|
``psplash`` from loading and thus allows you to see the console. It
|
|||
|
is also possible to switch out of the splashscreen by switching the
|
|||
|
virtual console (e.g. Fn+Left or Fn+Right on a Zaurus).
|
|||
|
|
|||
|
- Removing :term:`TMPDIR` (usually ``tmp/``, within the
|
|||
|
:term:`Build Directory`) can often fix temporary build issues. Removing
|
|||
|
:term:`TMPDIR` is usually a relatively cheap operation, because task output
|
|||
|
will be cached in :term:`SSTATE_DIR` (usually ``sstate-cache/``, which is
|
|||
|
also in the :term:`Build Directory`).
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Removing :term:`TMPDIR` might be a workaround rather than a fix.
|
|||
|
Consequently, trying to determine the underlying cause of an issue before
|
|||
|
removing the directory is a good idea.
|
|||
|
|
|||
|
- Understanding how a feature is used in practice within existing
|
|||
|
recipes can be very helpful. It is recommended that you configure
|
|||
|
some method that allows you to quickly search through files.
|
|||
|
|
|||
|
Using GNU Grep, you can use the following shell function to
|
|||
|
recursively search through common recipe-related files, skipping
|
|||
|
binary files, ``.git`` directories, and the :term:`Build Directory`
|
|||
|
(assuming its name starts with "build")::
|
|||
|
|
|||
|
g() {
|
|||
|
grep -Ir \
|
|||
|
--exclude-dir=.git \
|
|||
|
--exclude-dir='build*' \
|
|||
|
--include='*.bb*' \
|
|||
|
--include='*.inc*' \
|
|||
|
--include='*.conf*' \
|
|||
|
--include='*.py*' \
|
|||
|
"$@"
|
|||
|
}
|
|||
|
|
|||
|
Following are some usage examples::
|
|||
|
|
|||
|
$ g FOO # Search recursively for "FOO"
|
|||
|
$ g -i foo # Search recursively for "foo", ignoring case
|
|||
|
$ g -w FOO # Search recursively for "FOO" as a word, ignoring e.g. "FOOBAR"
|
|||
|
|
|||
|
If figuring
|
|||
|
out how some feature works requires a lot of searching, it might
|
|||
|
indicate that the documentation should be extended or improved. In
|
|||
|
such cases, consider filing a documentation bug using the Yocto
|
|||
|
Project implementation of
|
|||
|
:yocto_bugs:`Bugzilla <>`. For information on
|
|||
|
how to submit a bug against the Yocto Project, see the Yocto Project
|
|||
|
Bugzilla :yocto_wiki:`wiki page </Bugzilla_Configuration_and_Bug_Tracking>`
|
|||
|
and the ":doc:`../contributor-guide/report-defect`" section.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
The manuals might not be the right place to document variables
|
|||
|
that are purely internal and have a limited scope (e.g. internal
|
|||
|
variables used to implement a single ``.bbclass`` file).
|
|||
|
|