The debug process is an important step in every development cycle. In this chapter, we will understand how to configure Poky to help us with the debugging process, for example, how we can configure our system to provide the tools needed for a remote debug using GDB, how we can track our changes usingbuildhistory
, and how we can use a handy tool called devshell.
You're reading from Embedded Linux Development using Yocto Projects - Second Edition
When we first think about debugging, we usually don't realize that there are different types of debugging.
Metadata debugging is needed to ensure that the behavior of BitBake's tasks is aligned with our goals, and to identify the culprit when it's not. In this case, we use several log files generated by BitBake in the host in order to help trace the execution path of the involved task. As a consequence of a wrong behavior, a file may not be copied or a feature may not be enabled.
On the other hand, the debugging of runtime code is more natural for us as it is essentially the same as what we do during the normal development cycle of an application, a library, or a kernel. Depending on the kind of issue we are after, the right tool to help may vary from a debugger to code instrumentation (for example, adding debug prints).
In this chapter, we detail metadata debugging as it is the essence of the Yocto Project and supports us during the development...
The easiest way to ensure we have the image, packages, and SDK, along with the expected contents, is to use the Build History mechanism.
When a recipe is updated for a new version or has its code changed, it may influence the contents put in the generated packages and, as a consequence, in the image or SDK.
As Poky deals with a huge amount of recipes, and our images or SDKs frequently have tens or hundreds of packages included, it may be quite difficult to track the package contents. The Poky tool responsible for helping us in this task is the Build History.
The Build History, as we can guess from its name, keeps a history of the contents of several artifacts built during the use of Poky. It can track package, image, and SDK building.
To enable the Build History in our system, we need to add the following lines of code in our build/conf/local.conf
file:
INHERIT += "buildhistory" BUILDHISTORY_COMMIT = "1"
The INHERIT
method includes the buildhistory
class...
In more sophisticated recipes, we split the installed contents into several sub-packages. The sub-packages can be optional features, modules, or any other set of files that it is optional to install.
To inspect how the recipe's content has been split, we can use the build/tmp/work/<arch>/<recipe name>/<software version>/packages-split
directory. It contains a sub-directory for every sub-package and has its contents in the sub-tree.
Among the possible reasons for a mistaken content split, we have the following:
- Contents not being installed (for example, an error in installation scripts)
- Application or library configuration error (for example, a disabled feature)
- Metadata error (for example, wrong package order)
Another common issue that we find, mainly in library recipes, is that the required artifacts are not made available in the sysroot
directory (for example, headers or dynamic libraries), causing a build breakage. The counterpart of the sysroot
generation...
The logging utilities provided by BitBake are very useful for tracing the code execution path. BitBake provides logging functions for use in Python and Shell Script code, described as follows:
- Python: For use within Python functions, BitBake supports several log levels, which are
bb.fatal
,bb.error
,bb.warn
,bb.note
,bb.plain
, andbb.debug
- Shell Script: For use in Shell Script functions, the same set of log levels exists and is accessed with a similar syntax:
bbfatal
,bberror
,bbwarn
,bbnote
,bbplain
, andbbdebug
These logging functions are very similar to each other but have inner differences, described as follows:
bb.fatal
andbbfatal
: These have the highest priority of logging messages as they print the message and terminate the processing. They cause the build to be interrupted.bb.error
andbberror
: These are used to display an error but do not force the build to stop.bb.warn
andbbwarn
: These are used to warn users about something.bb.note
andbbnote...
When editing packages or debugging build failures, a development shell can be a useful tool. When we use devshell
, source files are extracted into the working directory, patches are applied, a new terminal is opened, and files are placed in the working directory.
In the new terminal, all the environment variables needed for the build are still defined, so we can use commands such as configure
and make
. The commands execute just as if the build system was executing them.
The following command is an example that uses devshell
on a target named linux-yocto
:
$ bitbake linux-yocto -c devshell
This allows us to rework the Linux kernel source code and build it in place, to avoid building it from scratch on our development machine, and change its code as needed.
Note
It is important to bear in mind that no changes made inside devshell
are persistent between builds; thus, we must be careful to record any change that is important, prior to leaving it.
As we have the source at...
While developing any project, from time to time we end up struggling to understand subtle bugs. The GNU Project Debugger (GDB) is available as a package within Poky and is installed in SDK images by default, as was detailed in Chapter 8, Developing with the Yocto Project.
Note
In order to install debugging packages that contain the debug symbols and debugging tools in an image, add IMAGE_FEATURES += "dbg-pkgs tools-debug"
in build/conf/local.conf
.
The use of the SDK, or an image with the debugging packages and tools installed, allows us to debug applications directly in the target, as we usually do on our development machine.
The GDB may not be usable on some targets because of memory or disk space constraints. The main reason for this limitation is the GDB needs to load the debugging information, along with the binaries of the process being debugged, before starting the debugging process.
To overcome these constraints, we can use gdbserver
, included...
In this chapter, we understood how we can configure Poky to help us with the debugging process. We learned the contents of deployed directories that can be used for debugging, how we can track our changes using buildhistory
, how we can use devshell
to emulate the same build environment found by BitBake, and how we configure our system to provide the tools needed for GDB debugging.
In the next chapter, we will understand how to expand the Poky source code using external layers. We will be introduced to the concept of layering, and we will learn in detail the directory structure and the content of each layer type.