1 First Program
1.1 First Steps
Using your favourite text editor, type the following program (without the line numbers) and save in a file named first.cpp:
1 #include <elm/io.h> 2 #include <otawa/otawa.h> 3 4 using namespace elm; 5 using namespace otawa; 6 7 int main(int argc, char **argv) { 8 try { 9 PropList props; 10 11 WorkSpace *ws = MANAGER.load(argv[1], props); 12 Address addr = ws->process()->findLabel("main"); 13 cout << "main found at " << addr << io::endl; 14 return 0; 15 } 16 catch(otawa::Exception& e) { 17 cerr << "ERROR: " << e.message() << io::endl; 18 return 1; 19 } 20 }
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 files. An otawa::File is composed of otawa::Segment and some otawa::Segment contain 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.
1.2 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.
1 CXXFLAGS += $(shell otawa-config --cflags) 2 LIBS += $(shell otawa-config --libs --rpath) 3 4 all: first 5 6 first: first.o 7 $(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
1.3 Details of the Load Process
The program executed in the previous section performed successfully but errors may appear. OTAWA allows to track this error using a verbose mode. To enable 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.
1.4 Using the Application Class
It is so common to open an ELF file, handling and displaying exceptions and, possibly, enabling the verbose mode that OTAWA provides a specific class: otawa::Application. It provides a lot of facilities like enabling the verbose mode using an argument flag, -v or –verbose.
Replace the content of first.cpp with the following and recompile the application:
1 #include <elm/io.h> 2 #include <otawa/otawa.h> 3 #include <otawa/app/Application.h> 4 5 using namespace elm; 6 using namespace otawa; 7 8 class First: public Application { 9 public: 10 First(void): Application("first", Version(1, 0, 0)) { } 11 12 protected: 13 void work(PropList &props) override { 14 Address addr = workspace()->process()->findLabel("main"); 15 cout << "main found at " << addr << io::endl; 16 } 17 18 }; 19 20 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
otawa::Address
otawa::Application
otawa::Exception
otawa::Manager
otawa::PropList
otawa::WorkSpace