Summary
This first lecture presents the basic concepts of OTAWA as an example program. Other learnt topics include how to to do aMakefile
to compile the program and an insight on an important concept of OTAWA: properties.
Table of Contents
First Steps
Using your favourite text editor, type the following program (without the line numbers) and save in a file named first.cpp
:
#include <elm/io.h> #include <otawa/otawa.h> using namespace elm; using namespace otawa; int main(int argc, char **argv) { try { PropList props; WorkSpace *ws = MANAGER.load(argv[1], props); Address addr = ws->process()->findLabel("main"); cout << "main found at " << addr << io::endl; return 0; } catch(otawa::Exception& e) { cerr << "ERROR: " << e.message() << io::endl; return 1; } }
Line 1 include the IO module of the ELM library: in OTAWA, we prefer to use the ELM library instead of the STL because it provides much more facilities. Yet, ELM provides several items with the same name than STL: for example, cout,
cerr
and cin
allows to perform input / output. Notice that ELM provides its facility in the elm
namespace that is opened at line 4.
Line 2 include the main header file for OTAWA. All OTAWA items are stored in the otawa
namespace that is opened at line 5.
Line 7 declares a standard C/C++ main program. Here we using the standard way to get arguments from the command line thanks to argc
, number of arguments, and argv
, list of arguments.
Line 8 declares a try
area where the otawa::Exception
exception is caught at line 16. All OTAWA errors are processed as exception and all OTAWA exceptions inherits from otawa::Exception
that makes easy to handle error in a unique point. Here, line 17, we display the error on the standard error output and stops the command, returning a non-zero exit code (line 18).
If there is no exception, the execution goes on to 9 where we declare a property list, otawa::PropList
. Property lists are widely used in OTAWA to store in kind of data. Basically, a property list is a collection of properties made of an identifier and of a data matching the type of the identifier. This object is only used to open the ELF file on the next line.
Line 11 opens the ELF file passed in the first argument of the command. MANAGER
is a constant object providing methods to open the file. The class of MANAGER
is otawa::Manager
and you can have details on this class the auto-documentation of OTAWA.
In this case, we just call the open()
method of Manager
class. It takes as first parameter the path of the file to open and, as second parameter, a property list used to configure the opening operation. For now, we let this list empty. If there is no error, this method opens the file, look for a loader plug-in and get a representation of the content of the file. The loader is responsible for loading the file in memory and providing a representation of the program (including the decoding of instructions composing the program). The result is an object of type otawa::WorkSpace
that is adapted to the analysis of programs in machine code.
An otawa::WorkSpace
allows to perform and store analyses performed on the machine code. It contains a link to the image of the program in memory called an otawa::Process
. An otawa::Process
is made of otawa::File
, that is, a main file and possibly opened library file. An otawa::File
is composed of otawa::Segment
and some otawa::Segment
contains instruction of class otawa::Inst
.
In our small example, we are only using the otawa::Process
object, line 13, to get the address of the main
function using the findLabel()
method. This one returns an object of type otawa::Address
that represents the address of the label. If the label is not found, the address is equal to Address::null
that represents an invalid address. This may be tested using the method Address::isNull()
on an address.
Finally, line 14, we display the found address. As the otawa::Address
class, a lot of OTAWA classes overload the <<
operator in order to be displayed on cout
or cerr
.
Compiling the OTAWA Program
To get this first program working, you have to compile it. Maybe, the easier way to achieve this, is to use a Makefile
. Copy the following Makefile
(without the line numbers) in the same directory as first.cpp
.
CXXFLAGS += $(shell otawa-config --cflags) LIBS += $(shell otawa-config --libs --rpath) all: first first: first.o $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS)
On line 1 and 2, we are using the command otawa-config
to get C++ compilation options, --cflags
, and linkage options, --libs
. --rpath
allows to avoid to add the OTAWA library to the dynamic retrieval path (LD_LIBRARY_PATH
on Unices). The compilation is performed on line 7 using classic Makefile
features and the defines variables. Then compile it by invoking make
:
$ make
If needed, fix the produced errors and re-launch the compilation until succeeding. At this point, it remains only C++ errors.
Then, you can launch the obtained command on an ELF file as bs.elf.
./first bs.elf
And you will get, as result:
warning: reverting to default arch plugin
warning: reverting to default sys plugin
warning: reverting to default arch plugin
warning: reverting to default sys plugin
main found at 00008218
You can safely ignore the warnings at the beginning. The main
address is 0x00008218.
Details of the Load Process
The program executed in the previous section performed successfully but errors may appears. OTAWA allows to track this error using a verbose mode. To activate it, just add the following source at line 10 and recompile the executable.
Processor::VERBOSE(props) = true;
This source line add the property of identifier Processor::VERBOSE
with value true
to props
property list. This syntax benefits from the operator overloading facilities of C++ to propose an easier and more readable syntax to assign properties to a property list. The generic rule is identifier (property list) = value where value is of a compatible type with identifier. identifier is a global object, of class p::id
, identifying uniquely the property and giving the type of the property value.
It must be noticed that most OTAWA objects inherit from PropList
and, therefore, support arbitrary properties.
Now, if the first
program is run, we get:
warning: reverting to default arch plugin warning: reverting to default sys plugin INFO: looking for loader "elf_40" INFO: prefix path = /home/casse/otawa/site/bin/.. INFO: searchpaths: INFO: - ./.otawa/loader INFO: - /home/casse/.otawa/loader INFO: - /home/casse/otawa/site/bin/../lib/otawa/loader INFO: - /home/casse/otawa/otawa/lib/otawa/loader INFO: - /home/casse/otawa/site/lib/otawa/loader INFO: available loaders INFO: - elf_44 (/home/casse/otawa/site/lib/otawa/loader/elf_44.so) INFO: - elf_2 (/home/casse/otawa/site/lib/otawa/loader/elf_2.so) INFO: - arm (/home/casse/otawa/site/lib/otawa/loader/arm.so) INFO: - sparc (/home/casse/otawa/site/lib/otawa/loader/sparc.so) INFO: - elf_20 (/home/casse/otawa/site/lib/otawa/loader/elf_20.so) INFO: - elf_44 (/home/casse/otawa/site/lib/otawa/loader/elf_44.so) INFO: - elf_2 (/home/casse/otawa/site/lib/otawa/loader/elf_2.so) INFO: - arm (/home/casse/otawa/site/lib/otawa/loader/arm.so) INFO: - sparc (/home/casse/otawa/site/lib/otawa/loader/sparc.so) INFO: - elf_20 (/home/casse/otawa/site/lib/otawa/loader/elf_20.so) INFO: selected loader: arm (2.0.0) ( /home/casse/otawa/site/bin/../lib/otawa/loader/elf_40.so) warning: reverting to default arch plugin warning: reverting to default sys plugin main found at 00008218
In this case, details of loader resolution from the identification found in the ELF file ##bs.elf## are displayed.
Using the Application Class
It is so common to open an ELF file, handling and displaying exceptions and, possibly, activating the verbose mode that OTAWA provides a specific class: otawa::Application
. It provides a lot of facilities like activating the verbose mode using an argument flag, -v
or --verbose
.
Replace the content of first.cpp
with the following and recompile the application:
#include <elm/io.h> #include <otawa/otawa.h> #include <otawa/app/Application.h> using namespace elm; using namespace otawa; class First: public Application { public: First(void): Application("first", Version(1, 0, 0)) { } protected: void work(PropList &props) override { Address addr = workspace()->process()->findLabel("main"); cout << "main found at " << addr << io::endl; } }; OTAWA_RUN(First)
The otawa::Application
parses the argument passed in the command line and open the path passed as first argument as an ELF file. If this is successful, it call the method work()
where the developer can put its own code. The given proplist contains the translation of some arguments as properties. It is advised to use it when you have to call methods requiring a property list. The current workspace is obtained with the method ##workspace()##. You can call ##first## command as usual but it may be more interesting to use the -v
switch to activate the verbose mode:
$ ./first -v
Usually, an OTAWA command takes as first parameter the executable file path and, as other parameters, names of function to process. To achieve this with OTAWA, you have to replace the work()
function by the following definition:
void work(const string &entry, PropList &props) override { Address addr = workspace()->process()->findLabel(entry); cout << entry << " found at " << addr << io::endl; }
This method will be called for each argument, after the first one considered as the executable file path, with a different workspace allowing to perform different analyses. In this example, we use this feature to compute the address of the labels passed in parameters.
Once compiled, the new command can be used as below:
$ ./first2 bs.elf main binary_search warning: reverting to default arch plugin warning: reverting to default sys plugin warning: reverting to default arch plugin warning: reverting to default sys plugin main found at 00008218 binary_search found at 00008234
Used Classes
- otawa::Address
- otawa::Application
- otawa::Exception
- otawa::Manager
- otawa::PropList
- otawa::WorkSpace
- options classes