Fjalar: A Dynamic Analysis Framework for C and C++ Programs
Programmer's Manual
Fjalar is a framework that facilitates
the construction of dynamic analysis tools for programs written in C
and C++. This document serves as a guide to building tools on top of
the Fjalar framework.
Getting Started
Here are the relevant entries in the directory structure after you
have un-tarred the Fjalar package (executables shown in bold):
- valgrind-3/
- auto-everything.sh
- valgrind/
- fjalar/
- Makefile.am
- fjalar_tool.h
- fjalar_include.h
- mc_main.c
- basic-tool/
- basic-tool.c
- basic-tool-test.c
- include/
- inst/
- bin/
- lib/
- valgrind/
- stage2
- vgtool_fjalar.so
- vgpreload_fjalar.so
Fjalar is implemented as a tool on top of the Valgrind binary instrumentation
framework, so that is why Valgrind's files dominate the directory
structure. Fjalar and its tools are located in the
valgrind-3/valgrind/fjalar sub-directory. The significance
of all of these files will be explained in this document.
Creating Fjalar tools
To create a new tool:
- Create a sub-directory in the valgrind-3/valgrind/fjalar
directory and place all of your tool's source files in there.
- Edit Makefile.am in valgrind-3/valgrind/fjalar
to include all the .c files of your tool by adding them to the
list of files assigned to the
vgtool_fjalar_so_SOURCES variable. (Feel free to tweak
other variables in that file. For instance, you can adjust
AM_CFLAGS to add optimizations. The default is to turn
optimizations off to ease debugging.)
- Run auto-everything.sh to create a new Makefile
from your modified Makefile.am and re-compile
everything. You only need to run auto-everything.sh
whenever you make a change to Makefile.am. (Notice
that directly editing Makefile and
Makefile.in is sub-optimal because they are
auto-generated from Makefile.am every time
auto-everything.sh is run).
- At this point, you'll probably get some compilation error. In
order for Fjalar to compile properly with your tool, your
tool's source files will need to implement all of the
functions listed in fjalar_tool.h. Include this
header file in one of your tool's source files and define
stubs for all of the functions (or just copy them from
basic-tool.c). Hopefully your tool should
compile properly now.
- If you've configured everything properly, you should be able to do
make and make install in the
valgrind-3/valgrind/fjalar directory to compile Fjalar and
your tool. Running make creates two shared libraries
vgpreload_fjalar.so and vgtool_fjalar.so, which are
dynamically-loaded by Valgrind during execution. Running make
install moves those shared libraries into
valgrind-3/valgrind/inst/lib/valgrind.
Programming tips for Fjalar tools:
- fjalar_include.h
contains all of the functions and data structures that Fjalar provides
for its tools. This file is fairly well-documented, so please read
over it to get a feel for what services are available to tools. Your
tool should only need to include this file (along with the mandatory
fjalar_tool.h),
but if it requires additional functionality, you can always
extern variables and functions from the other Fjalar source
files.
- Look at the code of basic-tool.c to see a simple
tool built on top of Fjalar. It prints out a list of variables at
every function entrance and exit and, if the variable refers to an
array of elements, the size of that array at the current point in
execution.
- Because Fjalar itself is implemented as a tool on top of Valgrind,
it interacts with Valgrind through functions defined in
tool.h. Your tool can also access those functions.
- DO NOT USE libc functions (e.g., printf,
malloc, strcpy) in your tool if there is an
alternative Valgrind version available in tool.h (Valgrind
implements a large subset of the standard C library). The Valgrind
version of functions will usually be wrapped by a VG_( )
macro. For example, the Valgrind version of malloc is named
VG_(malloc). We have had some bad experiences with
Valgrind's memory allocators conflicting with libc's allocators, so
please use the Valgrind functions at all times if possible to minimize
the chance of weird memory corruption errors. When in doubt, just
surround your libc function name with VG_( ).
- Use the tl_assert() macro (defined in tool.h) to
add assert statements in your code, which can be very helpful for
catching bugs.
- Use the --xml-output-file option when executing your
target program to see what data structures Fjalar can properly
recognize in the target program. This information can be helpful for
debugging.
Executing Fjalar tools
Here is the command for executing your tool:
valgrind-3/valgrind/inst/bin/valgrind --tool=fjalar <command-line args>
The actual executable is valgrind because Fjalar is
implemented as a Valgrind tool (and your Fjalar tool is compiled
together with Fjalar). This command can be fairly tedious to type, so
you should probably make a shell script to alias it. The only
mandatory command-line argument is the name of the target program (the
program to analyze). Use --help as one of your arguments to
view a list of command-line options.
In order for Fjalar to work, the target program must be compiled
with DWARF2 debugging information (on an x86/Linux system). Look at
basic-tool-test.c for a simple target program that exercises
Fjalar's function entrance/exit tracking and array bounds checking
features. First, compile it:
gcc -gdwarf-2 basic-tool-test.c -o basic-tool-test
(The -gdwarf-2 includes debugging information in the DWARF2
format.) Now you should be able to run Fjalar from this directory
(assuming that you have successfully compiled and installed it) with
the following command:
../../inst/bin/valgrind --tool=fjalar ./basic-tool-test
If all goes well, the tool should print out the name of each function
during entrances and exits and the names of all variables visible at
that point in execution (as well as array sizes, if relevant).
Here are some tips related to executing Fjalar tools:
- To change what messages are displayed when your tool starts up, you
can edit some strings within the TL_(pre_clo_init)() function
in mc_main.c.
- I believe that the standard Valgrind terminal printing functions,
most notably VG_(printf), output to standard error (file descriptor
2) by default, so you may find it useful to use 2>&1
to re-direct to standard output.
Debugging Fjalar tools
If you run your tool with the --with-gdb option, Fjalar will
pause in an infinite loop during initialization. You can then attach
a symbolic debugger such as gdb to the running process in
order to debug it:
- First start gdb with
valgrind-3/valgrind/inst/lib/valgrind/stage2 as the
target program (this is un-intuitive, but you need to run
gdb on stage2 and NOT on valgrind).
- Now use the at command to attach gdb to
the process that's stuck in the infinite loop. You can see its
process ID enclosed in "==" next to the start-up banner
(e.g., ==3839== ...), or simply ps for it.
if (fjalar_with_gdb) {
int x = 0;
while (!x) {}
}
- As shown in the code snippet above, Fjalar is stuck in an
infinite loop because x is 0. Set x to a
non-zero value, for instance by typing p x = 1, so that
it can get out of the infinite loop.
- Now set whatever breakpoints and/or watchpoints you desire,
and hit c to continue execution. You'll probably get a
mysterious Segmentation fault shortly afterwards, but
simply hit c to continue again, and things should work
fine. Valgrind mucks around with signals, so some error
messages sent to the debugger might not be accurate.
- You should now be able to debug as usual.
Fjalar command-line options
Fjalar provides a variety of command-line options to customize its
behavior and the behavior of its tools. These options are all
documented in the Kvasir
section of the Daikon User Manual. To prevent duplication, these
descriptions will not be repeated in this document. Kvasir
is a value profiling tool built upon Fjalar, so many options in that
section of the manual belong to Fjalar (some are Kvasir-specific,
though). Useful sub-sections include ones that describe tracing
only part of a program and pointer-type
disambiguation, which are two ways of giving the user more control
over run-time data structure traversals.
Philip Guo (pgbovine@mit.edu)
Last modified on Dec. 16, 2005