opimport.cpp

Go to the documentation of this file.
00001 
00011 #include "abi.h"
00012 #include "odb.h"
00013 #include "popt_options.h"
00014 #include "op_sample_file.h"
00015 
00016 #include <fstream>
00017 #include <iostream>
00018 #include <vector>
00019 #include <cassert>
00020 #include <cstring>
00021 #include <cstdlib>
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <fcntl.h>
00026 #include <unistd.h>
00027 #include <sys/mman.h>
00028 #include <cstdlib>
00029 #include <cstring>
00030 
00031 using namespace std;
00032 
00033 namespace {
00034     string output_filename;
00035     string abi_filename;
00036     bool verbose;
00037     bool force;
00038 };
00039 
00040 
00041 popt::option options_array[] = {
00042     popt::option(verbose, "verbose", 'V', "verbose output"),
00043     popt::option(output_filename, "output", 'o', "output to file", "filename"),
00044     popt::option(abi_filename, "abi", 'a', "abi description", "filename"),
00045     popt::option(force, "force", 'f', "force conversion, even if identical")
00046 };
00047 
00048 
00049 struct extractor {
00050 
00051     abi const & theabi;
00052 
00053     unsigned char const * begin;
00054     unsigned char const * end;
00055     bool little_endian;
00056 
00057     explicit
00058     extractor(abi const & a, unsigned char const * src, size_t len)
00059         : theabi(a), begin(src), end(src + len) {
00060         little_endian = theabi.need(string("little_endian")) == 1;
00061         if (verbose) {
00062             cerr << "source byte order is: "
00063                  << string(little_endian ? "little" : "big")
00064                  << " endian" << endl;
00065         }
00066     }
00067 
00068     template <typename T>
00069     void extract(T & targ, void const * src_,
00070                  char const * sz, char const * off);
00071 };
00072 
00073 
00074 template <typename T>
00075 void extractor::extract(T & targ, void const * src_,
00076                         char const * sz, char const * off)
00077 {
00078     unsigned char const * src = static_cast<unsigned char const *>(src_)
00079         + theabi.need(off);
00080     size_t nbytes = theabi.need(sz);
00081 
00082     targ = 0;
00083     if (nbytes == 0)
00084         return;
00085     
00086     assert(nbytes <= sizeof(T));
00087     assert(src >= begin);
00088     assert(src + nbytes <= end);
00089     
00090     if (verbose)
00091         cerr << hex << "get " << sz << " = " << nbytes
00092              << " bytes @ " << off << " = " << (src - begin)
00093              << " : ";
00094 
00095     if (little_endian)
00096         while(nbytes--)
00097             targ = (targ << 8) | src[nbytes];
00098     else
00099         for(size_t i = 0; i < nbytes; ++i)
00100             targ = (targ << 8) | src[i];
00101     
00102     if (verbose)
00103         cerr << " = " << targ << endl;
00104 }
00105 
00106 
00107 void import_from_abi(abi const & abi, void const * srcv,
00108                      size_t len, odb_t * dest) throw (abi_exception)
00109 {
00110     struct opd_header * head =
00111         static_cast<opd_header *>(odb_get_data(dest));
00112     unsigned char const * src = static_cast<unsigned char const *>(srcv);
00113     unsigned char const * const begin = src;
00114     extractor ext(abi, src, len);   
00115 
00116     memcpy(head->magic, src + abi.need("offsetof_header_magic"), 4);
00117 
00118     // begin extracting opd header
00119     ext.extract(head->version, src, "sizeof_u32", "offsetof_header_version");
00120     ext.extract(head->cpu_type, src, "sizeof_u32", "offsetof_header_cpu_type");
00121     ext.extract(head->ctr_event, src, "sizeof_u32", "offsetof_header_ctr_event");
00122     ext.extract(head->ctr_um, src, "sizeof_u32", "offsetof_header_ctr_um");
00123     ext.extract(head->ctr_count, src, "sizeof_u32", "offsetof_header_ctr_count");
00124     ext.extract(head->is_kernel, src, "sizeof_u32", "offsetof_header_is_kernel");
00125     // "double" extraction is unlikely to work
00126     head->cpu_speed = 0.0;
00127     ext.extract(head->mtime, src, "sizeof_u64", "offsetof_header_mtime");
00128     ext.extract(head->cg_to_is_kernel, src, "sizeof_u32",
00129         "offsetof_header_cg_to_is_kernel");
00130     ext.extract(head->anon_start, src, "sizeof_u32",
00131         "offsetof_header_anon_start");
00132     ext.extract(head->cg_to_anon_start, src, "sizeof_u32",
00133         "offsetof_header_cg_to_anon_start");
00134     src += abi.need("sizeof_struct_opd_header");
00135     // done extracting opd header
00136 
00137     // begin extracting necessary parts of descr
00138     odb_node_nr_t node_nr;
00139     ext.extract(node_nr, src, "sizeof_odb_node_nr_t", "offsetof_descr_current_size");
00140     src += abi.need("sizeof_odb_descr_t");
00141     // done extracting descr
00142 
00143     // skip node zero, it is reserved and contains nothing usefull
00144     src += abi.need("sizeof_odb_node_t");
00145 
00146     // begin extracting nodes
00147     unsigned int step = abi.need("sizeof_odb_node_t");
00148     if (verbose)
00149         cerr << "extracting " << node_nr << " nodes of " << step << " bytes each " << endl;
00150 
00151     assert(src + (node_nr * step) <= begin + len);
00152 
00153     for (odb_node_nr_t i = 1 ; i < node_nr ; ++i, src += step) {
00154         odb_key_t key;
00155         odb_value_t val;
00156         ext.extract(key, src, "sizeof_odb_key_t", "offsetof_node_key");
00157         ext.extract(val, src, "sizeof_odb_value_t", "offsetof_node_value");
00158         int rc = odb_add_node(dest, key, val);
00159         if (rc != EXIT_SUCCESS) {
00160             cerr << strerror(rc) << endl;
00161             exit(EXIT_FAILURE);
00162         }
00163     }
00164     // done extracting nodes
00165 }
00166 
00167 
00168 int main(int argc, char const ** argv)
00169 {
00170 
00171     vector<string> inputs;
00172     popt::parse_options(argc, argv, inputs);
00173 
00174     if (inputs.size() != 1) {
00175         cerr << "error: must specify exactly 1 input file" << endl;
00176         exit(1);
00177     }
00178 
00179     if (inputs[0].rfind(".jo") == inputs[0].size() - 3) {
00180         if (verbose) {
00181             cerr << "Found a .jo file. Import is not allowed or necessary. Done." << endl;
00182             cerr << inputs[0] << endl;
00183         }
00184         // Silently exit with success.
00185         exit(EXIT_SUCCESS);
00186     }
00187 
00188     abi current_abi, input_abi;
00189 
00190     {
00191         ifstream abi_file(abi_filename.c_str());
00192         if (!abi_file) {
00193             cerr << "error: cannot open abi file "
00194                  << abi_filename << endl;
00195             exit(1);
00196         }
00197         abi_file >> input_abi;
00198     }
00199 
00200     if (!force && current_abi == input_abi) {
00201         cerr << "input abi is identical to native. "
00202              << "no conversion necessary." << endl;
00203         exit(1);
00204     }
00205 
00206     int in_fd;
00207     struct stat statb;
00208     void * in;
00209     odb_t dest;
00210     int rc;
00211 
00212     assert((in_fd = open(inputs[0].c_str(), O_RDONLY)) > 0);        
00213     assert(fstat(in_fd, &statb) == 0);
00214     assert((in = mmap(0, statb.st_size, PROT_READ,
00215               MAP_PRIVATE, in_fd, 0)) != (void *)-1);
00216 
00217     rc = odb_open(&dest, output_filename.c_str(), ODB_RDWR,
00218               sizeof(struct opd_header));
00219     if (rc) {
00220         cerr << "odb_open() fail:\n"
00221              << strerror(rc) << endl;
00222         exit(EXIT_FAILURE);
00223     }
00224 
00225     try {
00226         import_from_abi(input_abi, in, statb.st_size, &dest);
00227     } catch (abi_exception & e) {
00228         cerr << "caught abi exception: " << e.desc << endl;
00229     }
00230 
00231     odb_close(&dest);
00232 
00233     assert(munmap(in, statb.st_size) == 0);
00234 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1