The Chronicles of Narnia has always been one my favorite series of books. Today, I'm not going to talk about dwarfs such as Trumpkin, the dwarf that appeared in Prince Caspian (check out the latest movie), but instead something called the DWARF Debugging Standard. DWARF is a file format used by compilers and debuggers to enable source level debugging. A compiler writes information into a generated executable file and a debugger reads the information so that when the program is run it can relate the execution back to the source code. These details are usually not important for somebody writing software for a workstation, but most engineers understand the basic concept that to use gdb to debug a program compiled with gcc they need to add -g on the gcc command line or they cannot see the source code when debugging. Often projects have a "debug" build that has -g and a "release" build that does not have -g (and maybe has more optimization flags turned on to get the highest performance).
We live in the world of SoC verification where the boundaries and dependencies between hardware and software make things more difficult. I have posted multiple times about topics that cause trouble. Posts like "Is anybody out there a software verification engineer?" and "Where's the Bridge to Cross the Great Divide?" are good examples. My conclusion is that software engineers generally know how to write and debug software. Hardware and hardware verification engineers generally know to create and verify hardware, but when these start mixing things get more difficult.
When working with customers we find that the most common model is for software engineers to hand off software to a logic simulation environment in the form of memory files, often in the Verilog readmemh format. The process goes something like this:
Take the C and assembly code and compile it, this example is an ARM compile flow.
armasm -32 -bigend -checkreglist -CPU 5T
-keep -apcs /inter -g \
-i include init.s -list init.lst -o
-ansi -c -cpu 5T -zo -bigend -fy -g -O2 -I include main.c -o main.o
The next step is to link the object files to create an executable file.
armlink -debug -scatter link.txt -remove
-noscanlib -info \
sizes,totals,veneers,unused -map -symbols
-xref main.o init.o \
test.map -o test.elf
Mind the virtual and physical addresses used in the program are not important, but for embedded software the memory layout is important.. To make sure the code is placed into the correct areas of of memory a link map is used. Here is an example.
E_TABLE +0 UNINIT
The final step is to take the ELF file and translate it into something that can be loaded into a simulation memory model.
% fromelf -vhx -32x1
test.elf -output rom.dat
The rom.dat file contains hex characters that can be loaded into a Verilog memory model when a simulation is run.
Now let's get back to DWARF.The first thing to discuss is the ELF file. ELF stands for Executable and Linking Format. ELF files are object files produced by the compiler and linker that are binary representations of the programs intended to be executed directly on a CPU. The standard for ELF defines the file format including a header and different sections that allow the files to be easily identified and understood in a machine independent way. Understanding the details of the file format is not normally required to develop software for embedded systems, but some familiarity helps. In the example above the ELF file is test.elf. Of course, the elf extension is not needed, but I use it to make it more obvious. So if a Cadence AE or somebody from the ISX team asks about the name or location of the ELF file for the test, you can be confident you know what and where it is.
The next thing the same Cadence AE or ISX team member will ask is if your ELF file was compiled with DWARF. Normally this means nothing more than -g but since there are so many different compilers for embedded processors, the -g is not universal and the actual compiler switch could be anything. Newer compilers are likely to have DWARF support, but older compilers may not have it or have a very old version of it.
What is DWARF?
Here are three good places to start to get up to speed on DWARF:
Why do we care about DWARF?
DWARF is useful for debugging, but also for software verification. DWARF information can be used to learn many things about a software program. A good place to start is the dwarfdump utility that can be downloaded from DA's web page (part of libdwarf). If you have Specman installed then you have dwarfdump already available, just type dwarfdump at the prompt to get the usage message.
Usage: dwarfdump <options> <object file>
-a print all .debug_* sections
-b print abbrev section
-c print loc section
-d dense: one line per entry (info section only)
-e ellipsis: short names for tags, attrs etc.
-f print dwarf frame section
-F print gnu .eh_frame section
-g (use incomplete loclist support)
-h print exception tables
-i rint info section
-k[aerty] check dwarf information
a do all checks-l print line section
e examine attributes of pubnames
r examine attr-tag relation
t examine tag trees
y examine type info
-m print macinfo section
-o print relocation info
-p print pubnames section
-r print aranges section
-s print string section
a print both sections-u<file> print sections only for specified file
f print static func section
v print static var section
-v verbose: show more information
-x name=<path> name dwarfdump.conf
-x abi=<abi> name abi in dwarfdump.conf
-w print weakname section
-y print type section
I showed some output from dwarfdump -l in my last post.
DWARF is used in the SimVision Plugin Embedded Software Trace. For more information read the ISX User Guide or the reference in my post called "Embedded Software Bugging and Debugging".
DWARF is also used by ISX for functional verification of software to automatically create verification environments for C code. Many software test tools read the source code to find out the details of the functions and variables to be tested. This is a good start, but some details in embedded systems are architecture specific and can only be obtained from the object files. Sizes of basic data types are a good example of this. The example below has expected sizes for various data types on a 32-bit machine, but often embedded processors have different sizes for data types that are not explicitly defined by the C standard.DWARF also provides details for user defined data types.
<1>< 72> DW_TAG_base_type
DW_AT_name unsigned int
<1>< 79> DW_TAG_base_type
DW_AT_name unsigned char
<1>< 96> DW_TAG_base_type
DW_AT_name short unsigned int
<1>< 118> DW_TAG_base_type
DW_AT_name long unsigned int
<1>< 139> DW_TAG_base_type
DW_AT_name signed char
Overall DWARF is useful to understand what is in an executable file. Just like other handy utilities like nm and strings, reading DWARF information with dwarfdump or readelf is another good trick to have in the bag.