Home | History | Annotate | Download | only in libabi
      1 /**
      2  * @file opimport.cpp
      3  * Import sample files from other ABI
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author Graydon Hoare
      9  */
     10 
     11 #include "abi.h"
     12 #include "odb.h"
     13 #include "popt_options.h"
     14 #include "op_sample_file.h"
     15 
     16 #include <fstream>
     17 #include <iostream>
     18 #include <vector>
     19 #include <cassert>
     20 #include <cstring>
     21 #include <cstdlib>
     22 
     23 #include <sys/types.h>
     24 #include <sys/stat.h>
     25 #include <fcntl.h>
     26 #include <unistd.h>
     27 #include <sys/mman.h>
     28 #include <cstdlib>
     29 #include <cstring>
     30 
     31 using namespace std;
     32 
     33 namespace {
     34 	string output_filename;
     35 	string abi_filename;
     36 	bool verbose;
     37 	bool force;
     38 };
     39 
     40 
     41 popt::option options_array[] = {
     42 	popt::option(verbose, "verbose", 'V', "verbose output"),
     43 	popt::option(output_filename, "output", 'o', "output to file", "filename"),
     44 	popt::option(abi_filename, "abi", 'a', "abi description", "filename"),
     45 	popt::option(force, "force", 'f', "force conversion, even if identical")
     46 };
     47 
     48 
     49 struct extractor {
     50 
     51 	abi const & theabi;
     52 
     53 	unsigned char const * begin;
     54 	unsigned char const * end;
     55 	bool little_endian;
     56 
     57 	explicit
     58 	extractor(abi const & a, unsigned char const * src, size_t len)
     59 		: theabi(a), begin(src), end(src + len) {
     60 		little_endian = theabi.need(string("little_endian")) == 1;
     61 		if (verbose) {
     62 			cerr << "source byte order is: "
     63 			     << string(little_endian ? "little" : "big")
     64 			     << " endian" << endl;
     65 		}
     66 	}
     67 
     68 	template <typename T>
     69 	void extract(T & targ, void const * src_,
     70 	             char const * sz, char const * off);
     71 };
     72 
     73 
     74 template <typename T>
     75 void extractor::extract(T & targ, void const * src_,
     76                         char const * sz, char const * off)
     77 {
     78 	unsigned char const * src = static_cast<unsigned char const *>(src_)
     79 		+ theabi.need(off);
     80 	size_t nbytes = theabi.need(sz);
     81 
     82 	if (nbytes == 0)
     83 		return;
     84 
     85 	assert(nbytes <= sizeof(T));
     86 	assert(src >= begin);
     87 	assert(src + nbytes <= end);
     88 
     89 	if (verbose)
     90 		cerr << hex << "get " << sz << " = " << nbytes
     91 		     << " bytes @ " << off << " = " << (src - begin)
     92 		     << " : ";
     93 
     94 	targ = 0;
     95 	if (little_endian)
     96 		while(nbytes--)
     97 			targ = (targ << 8) | src[nbytes];
     98 	else
     99 		for(size_t i = 0; i < nbytes; ++i)
    100 			targ = (targ << 8) | src[i];
    101 
    102 	if (verbose)
    103 		cerr << " = " << targ << endl;
    104 }
    105 
    106 
    107 void import_from_abi(abi const & abi, void const * srcv,
    108                      size_t len, odb_t * dest) throw (abi_exception)
    109 {
    110 	struct opd_header * head =
    111 		static_cast<opd_header *>(odb_get_data(dest));
    112 	unsigned char const * src = static_cast<unsigned char const *>(srcv);
    113 	unsigned char const * const begin = src;
    114 	extractor ext(abi, src, len);
    115 
    116 	memcpy(head->magic, src + abi.need("offsetof_header_magic"), 4);
    117 
    118 	// begin extracting opd header
    119 	ext.extract(head->version, src, "sizeof_u32", "offsetof_header_version");
    120 	ext.extract(head->cpu_type, src, "sizeof_u32", "offsetof_header_cpu_type");
    121 	ext.extract(head->ctr_event, src, "sizeof_u32", "offsetof_header_ctr_event");
    122 	ext.extract(head->ctr_um, src, "sizeof_u32", "offsetof_header_ctr_um");
    123 	ext.extract(head->ctr_count, src, "sizeof_u32", "offsetof_header_ctr_count");
    124 	ext.extract(head->is_kernel, src, "sizeof_u32", "offsetof_header_is_kernel");
    125 	// "double" extraction is unlikely to work
    126 	head->cpu_speed = 0.0;
    127 	ext.extract(head->mtime, src, "sizeof_time_t", "offsetof_header_mtime");
    128 	ext.extract(head->cg_to_is_kernel, src, "sizeof_u32",
    129 		"offsetof_header_cg_to_is_kernel");
    130 	ext.extract(head->anon_start, src, "sizeof_u32",
    131 		"offsetof_header_anon_start");
    132 	ext.extract(head->cg_to_anon_start, src, "sizeof_u32",
    133 		"offsetof_header_cg_to_anon_start");
    134 	src += abi.need("sizeof_struct_opd_header");
    135 	// done extracting opd header
    136 
    137 	// begin extracting necessary parts of descr
    138 	odb_node_nr_t node_nr;
    139 	ext.extract(node_nr, src, "sizeof_odb_node_nr_t", "offsetof_descr_current_size");
    140 	src += abi.need("sizeof_odb_descr_t");
    141 	// done extracting descr
    142 
    143 	// skip node zero, it is reserved and contains nothing usefull
    144 	src += abi.need("sizeof_odb_node_t");
    145 
    146 	// begin extracting nodes
    147 	unsigned int step = abi.need("sizeof_odb_node_t");
    148 	if (verbose)
    149 		cerr << "extracting " << node_nr << " nodes of " << step << " bytes each " << endl;
    150 
    151 	assert(src + (node_nr * step) <= begin + len);
    152 
    153 	for (odb_node_nr_t i = 1 ; i < node_nr ; ++i, src += step) {
    154 		odb_key_t key;
    155 		odb_value_t val;
    156 		ext.extract(key, src, "sizeof_odb_key_t", "offsetof_node_key");
    157 		ext.extract(val, src, "sizeof_odb_value_t", "offsetof_node_value");
    158 		int rc = odb_add_node(dest, key, val);
    159 		if (rc != EXIT_SUCCESS) {
    160 			cerr << strerror(rc) << endl;
    161 			exit(EXIT_FAILURE);
    162 		}
    163 	}
    164 	// done extracting nodes
    165 }
    166 
    167 
    168 int main(int argc, char const ** argv)
    169 {
    170 
    171 	vector<string> inputs;
    172 	popt::parse_options(argc, argv, inputs);
    173 
    174 	if (inputs.size() != 1) {
    175 		cerr << "error: must specify exactly 1 input file" << endl;
    176 		exit(1);
    177 	}
    178 
    179 	abi current_abi, input_abi;
    180 
    181 	{
    182 		ifstream abi_file(abi_filename.c_str());
    183 		if (!abi_file) {
    184 			cerr << "error: cannot open abi file "
    185 			     << abi_filename << endl;
    186 			exit(1);
    187 		}
    188 		abi_file >> input_abi;
    189 	}
    190 
    191 	if (!force && current_abi == input_abi) {
    192 		cerr << "input abi is identical to native. "
    193 		     << "no conversion necessary." << endl;
    194 		exit(1);
    195 	}
    196 
    197 	int in_fd;
    198 	struct stat statb;
    199 	void * in;
    200 	odb_t dest;
    201 	int rc;
    202 
    203 	assert((in_fd = open(inputs[0].c_str(), O_RDONLY)) > 0);
    204 	assert(fstat(in_fd, &statb) == 0);
    205 	assert((in = mmap(0, statb.st_size, PROT_READ,
    206 			  MAP_PRIVATE, in_fd, 0)) != (void *)-1);
    207 
    208 	rc = odb_open(&dest, output_filename.c_str(), ODB_RDWR,
    209 		      sizeof(struct opd_header));
    210 	if (rc) {
    211 		cerr << "odb_open() fail:\n"
    212 		     << strerror(rc) << endl;
    213 		exit(EXIT_FAILURE);
    214 	}
    215 
    216 	try {
    217 		import_from_abi(input_abi, in, statb.st_size, &dest);
    218 	} catch (abi_exception & e) {
    219 		cerr << "caught abi exception: " << e.desc << endl;
    220 	}
    221 
    222 	odb_close(&dest);
    223 
    224 	assert(munmap(in, statb.st_size) == 0);
    225 }
    226