The Android Open Source Project | 10e23ee | 2009-03-03 19:30:30 -0800 | [diff] [blame^] | 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 | } |