tools/reorder/garope.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6
michael@0 7 A program that attempts to find an optimal function ordering for an
michael@0 8 executable using a genetic algorithm whose fitness function is
michael@0 9 computed using runtime profile information.
michael@0 10
michael@0 11 The fitness function was inspired by Nat Friedman's <nat@nat.org>
michael@0 12 work on `grope':
michael@0 13
michael@0 14 _GNU Rope - A Subroutine Position Optimizer_
michael@0 15 <http://www.hungry.com/~shaver/grope/grope.ps>
michael@0 16
michael@0 17 Brendan Eich <brendan@mozilla.org> told me tales about Scott Furman
michael@0 18 doing something like this, which sort of made me want to try it.
michael@0 19
michael@0 20 As far as I can tell, it would take a lot of computers a lot of time
michael@0 21 to actually find something useful on a non-trivial program using
michael@0 22 this.
michael@0 23
michael@0 24 */
michael@0 25
michael@0 26 #include <assert.h>
michael@0 27 #include <fstream>
michael@0 28 #include <hash_map>
michael@0 29 #include <vector>
michael@0 30 #include <limits.h>
michael@0 31 #include <unistd.h>
michael@0 32 #include <stdio.h>
michael@0 33 #include <fcntl.h>
michael@0 34
michael@0 35 #include "elf_symbol_table.h"
michael@0 36
michael@0 37 #define _GNU_SOURCE
michael@0 38 #include <getopt.h>
michael@0 39
michael@0 40 #define PAGE_SIZE 4096
michael@0 41 #define SYMBOL_ALIGN 4
michael@0 42
michael@0 43 //----------------------------------------------------------------------
michael@0 44
michael@0 45 class call_pair
michael@0 46 {
michael@0 47 public:
michael@0 48 const Elf32_Sym *m_lo;
michael@0 49 const Elf32_Sym *m_hi;
michael@0 50
michael@0 51 call_pair(const Elf32_Sym *site1, const Elf32_Sym *site2)
michael@0 52 {
michael@0 53 if (site1 < site2) {
michael@0 54 m_lo = site1;
michael@0 55 m_hi = site2;
michael@0 56 }
michael@0 57 else {
michael@0 58 m_hi = site1;
michael@0 59 m_lo = site2;
michael@0 60 }
michael@0 61 }
michael@0 62
michael@0 63 friend bool
michael@0 64 operator==(const call_pair &lhs, const call_pair &rhs)
michael@0 65 {
michael@0 66 return (lhs.m_lo == rhs.m_lo) && (lhs.m_hi == rhs.m_hi);
michael@0 67 }
michael@0 68 };
michael@0 69
michael@0 70 // Straight outta plhash.c!
michael@0 71 #define GOLDEN_RATIO 0x9E3779B9U
michael@0 72
michael@0 73 template<>
michael@0 74 struct hash<call_pair>
michael@0 75 {
michael@0 76 size_t operator()(const call_pair &pair) const
michael@0 77 {
michael@0 78 size_t h = (reinterpret_cast<size_t>(pair.m_hi) >> 4);
michael@0 79 h += (reinterpret_cast<size_t>(pair.m_lo) >> 4);
michael@0 80 h *= GOLDEN_RATIO;
michael@0 81 return h;
michael@0 82 }
michael@0 83 };
michael@0 84
michael@0 85 //----------------------------------------------------------------------
michael@0 86
michael@0 87 struct hash<const Elf32_Sym *>
michael@0 88 {
michael@0 89 size_t operator()(const Elf32_Sym *sym) const
michael@0 90 {
michael@0 91 return (reinterpret_cast<size_t>(sym) >> 4) * GOLDEN_RATIO;
michael@0 92 }
michael@0 93 };
michael@0 94
michael@0 95 //----------------------------------------------------------------------
michael@0 96
michael@0 97 typedef hash_map<call_pair, unsigned int> call_graph_t;
michael@0 98 call_graph_t call_graph;
michael@0 99
michael@0 100 typedef hash_map<const Elf32_Sym *, unsigned int> histogram_t;
michael@0 101 histogram_t histogram;
michael@0 102 long long total_calls = 0;
michael@0 103
michael@0 104 elf_symbol_table symtab;
michael@0 105
michael@0 106 bool opt_debug = false;
michael@0 107 int opt_generations = 10;
michael@0 108 int opt_mutate = 0;
michael@0 109 const char *opt_out = "order.out";
michael@0 110 int opt_population_size = 100;
michael@0 111 int opt_tick = 0;
michael@0 112 bool opt_verbose = false;
michael@0 113 int opt_window = 0;
michael@0 114
michael@0 115 static struct option long_options[] = {
michael@0 116 { "debug", no_argument, 0, 'd' },
michael@0 117 { "exe", required_argument, 0, 'e' },
michael@0 118 { "generations", required_argument, 0, 'g' },
michael@0 119 { "help", no_argument, 0, '?' },
michael@0 120 { "mutate", required_argument, 0, 'm' },
michael@0 121 { "out", required_argument, 0, 'o' },
michael@0 122 { "population", required_argument, 0, 'p' },
michael@0 123 { "seed", required_argument, 0, 's' },
michael@0 124 { "tick", optional_argument, 0, 't' },
michael@0 125 { "verbose", no_argument, 0, 'v' },
michael@0 126 { "window", required_argument, 0, 'w' },
michael@0 127 { 0, 0, 0, 0 }
michael@0 128 };
michael@0 129
michael@0 130 //----------------------------------------------------------------------
michael@0 131
michael@0 132 static long long
michael@0 133 llrand()
michael@0 134 {
michael@0 135 long long result;
michael@0 136 result = (long long) rand();
michael@0 137 result *= (long long) (unsigned int) (RAND_MAX + 1);
michael@0 138 result += (long long) rand();
michael@0 139 return result;
michael@0 140 }
michael@0 141
michael@0 142 //----------------------------------------------------------------------
michael@0 143
michael@0 144 class symbol_order {
michael@0 145 public:
michael@0 146 typedef vector<const Elf32_Sym *> vector_t;
michael@0 147 typedef long long score_t;
michael@0 148
michael@0 149 static const score_t max_score;
michael@0 150
michael@0 151 /**
michael@0 152 * A vector of symbols that is this ordering.
michael@0 153 */
michael@0 154 vector_t m_ordering;
michael@0 155
michael@0 156 /**
michael@0 157 * The symbol ordering's score.
michael@0 158 */
michael@0 159 score_t m_score;
michael@0 160
michael@0 161 symbol_order() : m_score(0) {}
michael@0 162
michael@0 163 /**
michael@0 164 * ``Shuffle'' a symbol ordering, randomizing it.
michael@0 165 */
michael@0 166 void shuffle();
michael@0 167
michael@0 168 /**
michael@0 169 * Initialize this symbol ordering by performing a crossover from
michael@0 170 * two ``parent'' symbol orderings.
michael@0 171 */
michael@0 172 void crossover_from(const symbol_order *father, const symbol_order *mother);
michael@0 173
michael@0 174 /**
michael@0 175 * Randomly mutate this symbol ordering.
michael@0 176 */
michael@0 177 void mutate();
michael@0 178
michael@0 179 /**
michael@0 180 * Score a symbol ordering based on paginated locality.
michael@0 181 */
michael@0 182 score_t compute_score_page();
michael@0 183
michael@0 184 /**
michael@0 185 * Score a symbol ordering based on a sliding window.
michael@0 186 */
michael@0 187 score_t compute_score_window(int window_size);
michael@0 188
michael@0 189 static score_t compute_score(symbol_order &order);
michael@0 190
michael@0 191 /**
michael@0 192 * Use the symbol table to dump the ordered symbolic constants.
michael@0 193 */
michael@0 194 void dump_symbols() const;
michael@0 195
michael@0 196 friend ostream &
michael@0 197 operator<<(ostream &out, const symbol_order &order);
michael@0 198 };
michael@0 199
michael@0 200 const symbol_order::score_t
michael@0 201 symbol_order::max_score = ~((symbol_order::score_t)1 << ((sizeof(symbol_order::score_t) * 8) - 1));
michael@0 202
michael@0 203 symbol_order::score_t
michael@0 204 symbol_order::compute_score_page()
michael@0 205 {
michael@0 206 m_score = 0;
michael@0 207
michael@0 208 unsigned int off = 0; // XXX in reality, probably not page-aligned to start
michael@0 209
michael@0 210 vector_t::const_iterator end = m_ordering.end(),
michael@0 211 last = end,
michael@0 212 sym = m_ordering.begin();
michael@0 213
michael@0 214 while (sym != end) {
michael@0 215 vector_t page;
michael@0 216
michael@0 217 // If we had a symbol that spilled over from the last page,
michael@0 218 // then include it here.
michael@0 219 if (last != end)
michael@0 220 page.push_back(*last);
michael@0 221
michael@0 222 // Pack symbols into the page
michael@0 223 do {
michael@0 224 page.push_back(*sym);
michael@0 225
michael@0 226 int size = (*sym)->st_size;
michael@0 227 size += SYMBOL_ALIGN - 1;
michael@0 228 size &= ~(SYMBOL_ALIGN - 1);
michael@0 229
michael@0 230 off += size;
michael@0 231 } while (++sym != end && off < PAGE_SIZE);
michael@0 232
michael@0 233 // Remember if there was spill-over.
michael@0 234 off %= PAGE_SIZE;
michael@0 235 last = (off != 0) ? sym : end;
michael@0 236
michael@0 237 // Now score the page as the count of all calls to symbols on
michael@0 238 // the page, less calls between the symbols on the page.
michael@0 239 vector_t::const_iterator page_end = page.end();
michael@0 240 for (vector_t::const_iterator i = page.begin(); i != page_end; ++i) {
michael@0 241 histogram_t::const_iterator func = histogram.find(*i);
michael@0 242 if (func == histogram.end())
michael@0 243 continue;
michael@0 244
michael@0 245 m_score += func->second;
michael@0 246
michael@0 247 vector_t::const_iterator j = i;
michael@0 248 for (++j; j != page_end; ++j) {
michael@0 249 call_graph_t::const_iterator call =
michael@0 250 call_graph.find(call_pair(*i, *j));
michael@0 251
michael@0 252 if (call != call_graph.end())
michael@0 253 m_score -= call->second;
michael@0 254 }
michael@0 255 }
michael@0 256 }
michael@0 257
michael@0 258 assert(m_score >= 0);
michael@0 259
michael@0 260 // Integer reciprocal so we minimize instead of maximize.
michael@0 261 if (m_score == 0)
michael@0 262 m_score = 1;
michael@0 263
michael@0 264 m_score = (total_calls / m_score) + 1;
michael@0 265
michael@0 266 return m_score;
michael@0 267 }
michael@0 268
michael@0 269 symbol_order::score_t
michael@0 270 symbol_order::compute_score_window(int window_size)
michael@0 271 {
michael@0 272 m_score = 0;
michael@0 273
michael@0 274 vector_t::const_iterator *window = new vector_t::const_iterator[window_size];
michael@0 275 int window_fill = 0;
michael@0 276
michael@0 277 vector_t::const_iterator end = m_ordering.end(),
michael@0 278 sym = m_ordering.begin();
michael@0 279
michael@0 280 for (; sym != end; ++sym) {
michael@0 281 histogram_t::const_iterator func = histogram.find(*sym);
michael@0 282 if (func != histogram.end()) {
michael@0 283 long long scale = ((long long) 1) << window_size;
michael@0 284
michael@0 285 m_score += func->second * scale * 2;
michael@0 286
michael@0 287 vector_t::const_iterator *limit = window + window_fill;
michael@0 288 vector_t::const_iterator *iter;
michael@0 289 for (iter = window ; iter < limit; ++iter) {
michael@0 290 call_graph_t::const_iterator call =
michael@0 291 call_graph.find(call_pair(*sym, **iter));
michael@0 292
michael@0 293 if (call != call_graph.end())
michael@0 294 m_score -= (call->second * scale);
michael@0 295
michael@0 296 scale >>= 1;
michael@0 297 }
michael@0 298 }
michael@0 299
michael@0 300 // Slide the window.
michael@0 301 vector_t::const_iterator *begin = window;
michael@0 302 vector_t::const_iterator *iter;
michael@0 303 for (iter = window + (window_size - 1); iter > begin; --iter)
michael@0 304 *iter = *(iter - 1);
michael@0 305
michael@0 306 if (window_fill < window_size)
michael@0 307 ++window_fill;
michael@0 308
michael@0 309 *window = sym;
michael@0 310 }
michael@0 311
michael@0 312 delete[] window;
michael@0 313
michael@0 314 assert(m_score >= 0);
michael@0 315
michael@0 316 // Integer reciprocal so we minimize instead of maximize.
michael@0 317 if (m_score == 0)
michael@0 318 m_score = 1;
michael@0 319
michael@0 320 m_score = (total_calls / m_score) + 1;
michael@0 321
michael@0 322 return m_score;
michael@0 323 }
michael@0 324
michael@0 325 symbol_order::score_t
michael@0 326 symbol_order::compute_score(symbol_order &order)
michael@0 327 {
michael@0 328 if (opt_window)
michael@0 329 return order.compute_score_window(opt_window);
michael@0 330
michael@0 331 return order.compute_score_page();
michael@0 332 }
michael@0 333
michael@0 334 void
michael@0 335 symbol_order::shuffle()
michael@0 336 {
michael@0 337 vector_t::iterator sym = m_ordering.begin();
michael@0 338 vector_t::iterator end = m_ordering.end();
michael@0 339 for (; sym != end; ++sym) {
michael@0 340 int i = rand() % m_ordering.size();
michael@0 341 const Elf32_Sym *temp = *sym;
michael@0 342 *sym = m_ordering[i];
michael@0 343 m_ordering[i] = temp;
michael@0 344 }
michael@0 345 }
michael@0 346
michael@0 347 void
michael@0 348 symbol_order::crossover_from(const symbol_order *father, const symbol_order *mother)
michael@0 349 {
michael@0 350 histogram_t used;
michael@0 351
michael@0 352 m_ordering = vector_t(father->m_ordering.size(), 0);
michael@0 353
michael@0 354 vector_t::const_iterator parent_sym = father->m_ordering.begin();
michael@0 355 vector_t::iterator sym = m_ordering.begin();
michael@0 356 vector_t::iterator end = m_ordering.end();
michael@0 357
michael@0 358 for (; sym != end; ++sym, ++parent_sym) {
michael@0 359 if (rand() % 2) {
michael@0 360 *sym = *parent_sym;
michael@0 361 used[*parent_sym] = 1;
michael@0 362 }
michael@0 363 }
michael@0 364
michael@0 365 parent_sym = mother->m_ordering.begin();
michael@0 366 sym = m_ordering.begin();
michael@0 367
michael@0 368 for (; sym != end; ++sym) {
michael@0 369 if (! *sym) {
michael@0 370 while (used[*parent_sym])
michael@0 371 ++parent_sym;
michael@0 372
michael@0 373 *sym = *parent_sym++;
michael@0 374 }
michael@0 375 }
michael@0 376 }
michael@0 377
michael@0 378 void
michael@0 379 symbol_order::mutate()
michael@0 380 {
michael@0 381 int i, j;
michael@0 382 i = rand() % m_ordering.size();
michael@0 383 j = rand() % m_ordering.size();
michael@0 384
michael@0 385 const Elf32_Sym *temp = m_ordering[i];
michael@0 386 m_ordering[i] = m_ordering[j];
michael@0 387 m_ordering[j] = temp;
michael@0 388 }
michael@0 389
michael@0 390 void
michael@0 391 symbol_order::dump_symbols() const
michael@0 392 {
michael@0 393 ofstream out(opt_out);
michael@0 394
michael@0 395 vector_t::const_iterator sym = m_ordering.begin();
michael@0 396 vector_t::const_iterator end = m_ordering.end();
michael@0 397 for (; sym != end; ++sym)
michael@0 398 out << symtab.get_symbol_name(*sym) << endl;
michael@0 399
michael@0 400 out.close();
michael@0 401 }
michael@0 402
michael@0 403 ostream &
michael@0 404 operator<<(ostream &out, const symbol_order &order)
michael@0 405 {
michael@0 406 out << "symbol_order(" << order.m_score << ") ";
michael@0 407
michael@0 408 symbol_order::vector_t::const_iterator sym = order.m_ordering.begin();
michael@0 409 symbol_order::vector_t::const_iterator end = order.m_ordering.end();
michael@0 410 for (; sym != end; ++sym)
michael@0 411 out.form("%08x ", *sym);
michael@0 412
michael@0 413 out << endl;
michael@0 414
michael@0 415 return out;
michael@0 416 }
michael@0 417
michael@0 418 //----------------------------------------------------------------------
michael@0 419
michael@0 420 static void
michael@0 421 usage(const char *name)
michael@0 422 {
michael@0 423 cerr << "usage: " << name << " [options] [<file> ...]" << endl;
michael@0 424 cerr << " Options:" << endl;
michael@0 425 cerr << " --debug, -d" << endl;
michael@0 426 cerr << " Print lots of verbose debugging cruft." << endl;
michael@0 427 cerr << " --exe=<image>, -e <image> (required)" << endl;
michael@0 428 cerr << " Specify the executable image from which to read symbol information." << endl;
michael@0 429 cerr << " --generations=<num>, -g <num>" << endl;
michael@0 430 cerr << " Specify the number of generations to run the GA (default is 10)." << endl;
michael@0 431 cerr << " --help, -?" << endl;
michael@0 432 cerr << " Print this message and exit." << endl;
michael@0 433 cerr << " --mutate=<num>, -m <num>" << endl;
michael@0 434 cerr << " Mutate every <num>th individual, or zero for no mutation (default)." << endl;
michael@0 435 cerr << " --out=<file>, -o <file>" << endl;
michael@0 436 cerr << " Specify the output file to which to dump the symbol ordering of the" << endl;
michael@0 437 cerr << " best individual (default is `order.out')." << endl;
michael@0 438 cerr << " --population=<num>, -p <num>" << endl;
michael@0 439 cerr << " Set the population size to <num> individuals (default is 100)." << endl;
michael@0 440 cerr << " --seed=<num>, -s <num>" << endl;
michael@0 441 cerr << " Specify a seed to srand()." << endl;
michael@0 442 cerr << " --tick[=<num>], -t [<num>]" << endl;
michael@0 443 cerr << " When reading address data, print a dot to stderr every <num>th" << endl;
michael@0 444 cerr << " address processed from the call trace. If specified with no argument," << endl;
michael@0 445 cerr << " a dot will be printed for every million addresses processed." << endl;
michael@0 446 cerr << " --verbose, -v" << endl;
michael@0 447 cerr << " Issue progress messages to stderr." << endl;
michael@0 448 cerr << " --window=<num>, -w <num>" << endl;
michael@0 449 cerr << " Use a sliding window instead of pagination to score orderings." << endl;
michael@0 450 cerr << endl;
michael@0 451 cerr << "This program uses a genetic algorithm to produce an `optimal' ordering for" << endl;
michael@0 452 cerr << "an executable based on call patterns." << endl;
michael@0 453 cerr << endl;
michael@0 454 cerr << "Addresses from a call trace are read as binary data from the files" << endl;
michael@0 455 cerr << "specified, or from stdin if no files are specified. These addresses" << endl;
michael@0 456 cerr << "are used with the symbolic information from the executable to create" << endl;
michael@0 457 cerr << "a call graph. This call graph is used to `score' arbitrary symbol" << endl;
michael@0 458 cerr << "orderings, and provides the fitness function for the GA." << endl;
michael@0 459 cerr << endl;
michael@0 460 }
michael@0 461
michael@0 462 /**
michael@0 463 * Using the symbol table, map a stream of address references into a
michael@0 464 * callgraph and a histogram.
michael@0 465 */
michael@0 466 static void
michael@0 467 map_addrs(int fd)
michael@0 468 {
michael@0 469 const Elf32_Sym *last = 0;
michael@0 470 unsigned int buf[128];
michael@0 471 ssize_t cb;
michael@0 472
michael@0 473 unsigned int count = 0;
michael@0 474 while ((cb = read(fd, buf, sizeof buf)) > 0) {
michael@0 475 if (cb % sizeof buf[0])
michael@0 476 fprintf(stderr, "unaligned read\n");
michael@0 477
michael@0 478 unsigned int *addr = buf;
michael@0 479 unsigned int *limit = buf + (cb / 4);
michael@0 480
michael@0 481 for (; addr < limit; ++addr) {
michael@0 482 const Elf32_Sym *sym = symtab.lookup(*addr);
michael@0 483
michael@0 484 if (last && sym && last != sym) {
michael@0 485 ++total_calls;
michael@0 486 ++histogram[sym];
michael@0 487 ++call_graph[call_pair(last, sym)];
michael@0 488
michael@0 489 if (opt_tick && (++count % opt_tick == 0)) {
michael@0 490 cerr << ".";
michael@0 491 flush(cerr);
michael@0 492 }
michael@0 493 }
michael@0 494
michael@0 495 last = sym;
michael@0 496 }
michael@0 497 }
michael@0 498
michael@0 499 if (opt_tick)
michael@0 500 cerr << endl;
michael@0 501
michael@0 502 cerr << "Total calls: " << total_calls << endl;
michael@0 503 total_calls *= 1024;
michael@0 504
michael@0 505 if (opt_window)
michael@0 506 total_calls <<= (opt_window + 1);
michael@0 507 }
michael@0 508
michael@0 509 static symbol_order *
michael@0 510 pick_parent(symbol_order *ordering, int max, int index)
michael@0 511 {
michael@0 512 while (1) {
michael@0 513 index -= ordering->m_score;
michael@0 514 if (index < 0)
michael@0 515 break;
michael@0 516
michael@0 517 ++ordering;
michael@0 518 }
michael@0 519
michael@0 520 return ordering;
michael@0 521 }
michael@0 522
michael@0 523 /**
michael@0 524 * The main program
michael@0 525 */
michael@0 526 int
michael@0 527 main(int argc, char *argv[])
michael@0 528 {
michael@0 529 const char *opt_exe = 0;
michael@0 530
michael@0 531 int c;
michael@0 532 while (1) {
michael@0 533 int option_index = 0;
michael@0 534 c = getopt_long(argc, argv, "?de:g:m:o:p:s:t:vw:", long_options, &option_index);
michael@0 535
michael@0 536 if (c < 0)
michael@0 537 break;
michael@0 538
michael@0 539 switch (c) {
michael@0 540 case '?':
michael@0 541 usage(argv[0]);
michael@0 542 return 0;
michael@0 543
michael@0 544 case 'd':
michael@0 545 opt_debug = true;
michael@0 546 break;
michael@0 547
michael@0 548 case 'e':
michael@0 549 opt_exe = optarg;
michael@0 550 break;
michael@0 551
michael@0 552 case 'g':
michael@0 553 opt_generations = atoi(optarg);
michael@0 554 break;
michael@0 555
michael@0 556 case 'm':
michael@0 557 opt_mutate = atoi(optarg);
michael@0 558 break;
michael@0 559
michael@0 560 case 'o':
michael@0 561 opt_out = optarg;
michael@0 562 break;
michael@0 563
michael@0 564 case 'p':
michael@0 565 opt_population_size = atoi(optarg);
michael@0 566 break;
michael@0 567
michael@0 568 case 's':
michael@0 569 srand(atoi(optarg));
michael@0 570 break;
michael@0 571
michael@0 572 case 't':
michael@0 573 opt_tick = optarg ? atoi(optarg) : 1000000;
michael@0 574 break;
michael@0 575
michael@0 576 case 'v':
michael@0 577 opt_verbose = true;
michael@0 578 break;
michael@0 579
michael@0 580 case 'w':
michael@0 581 opt_window = atoi(optarg);
michael@0 582 if (opt_window < 0 || opt_window > 8) {
michael@0 583 cerr << "invalid window size: " << opt_window << endl;
michael@0 584 return 1;
michael@0 585 }
michael@0 586
michael@0 587 break;
michael@0 588
michael@0 589 default:
michael@0 590 usage(argv[0]);
michael@0 591 return 1;
michael@0 592 }
michael@0 593 }
michael@0 594
michael@0 595 // Make sure an image was specified
michael@0 596 if (! opt_exe) {
michael@0 597 usage(argv[0]);
michael@0 598 return 1;
michael@0 599 }
michael@0 600
michael@0 601 // Read the sym table.
michael@0 602 symtab.init(opt_exe);
michael@0 603
michael@0 604 // Process addresses to construct the call graph.
michael@0 605 if (optind >= argc) {
michael@0 606 map_addrs(STDIN_FILENO);
michael@0 607 }
michael@0 608 else {
michael@0 609 do {
michael@0 610 int fd = open(argv[optind], O_RDONLY);
michael@0 611 if (fd < 0) {
michael@0 612 perror(argv[optind]);
michael@0 613 return 1;
michael@0 614 }
michael@0 615
michael@0 616 map_addrs(fd);
michael@0 617 close(fd);
michael@0 618 } while (++optind < argc);
michael@0 619 }
michael@0 620
michael@0 621 if (opt_debug) {
michael@0 622 cerr << "Call graph:" << endl;
michael@0 623
michael@0 624 call_graph_t::const_iterator limit = call_graph.end();
michael@0 625 call_graph_t::const_iterator i;
michael@0 626 for (i = call_graph.begin(); i != limit; ++i) {
michael@0 627 const call_pair& pair = i->first;
michael@0 628 cerr.form("%08x %08x %10d\n",
michael@0 629 pair.m_lo->st_value,
michael@0 630 pair.m_hi->st_value,
michael@0 631 i->second);
michael@0 632 }
michael@0 633 }
michael@0 634
michael@0 635 // Collect the symbols into a vector
michael@0 636 symbol_order::vector_t ordering;
michael@0 637 elf_symbol_table::const_iterator end = symtab.end();
michael@0 638 for (elf_symbol_table::const_iterator sym = symtab.begin(); sym != end; ++sym) {
michael@0 639 if (symtab.is_function(sym))
michael@0 640 ordering.push_back(sym);
michael@0 641 }
michael@0 642
michael@0 643 if (opt_verbose) {
michael@0 644 symbol_order initial;
michael@0 645 initial.m_ordering = ordering;
michael@0 646 cerr << "created initial ordering, score=" << symbol_order::compute_score(initial) << endl;
michael@0 647
michael@0 648 if (opt_debug)
michael@0 649 cerr << initial;
michael@0 650 }
michael@0 651
michael@0 652 // Create a population.
michael@0 653 if (opt_verbose)
michael@0 654 cerr << "creating population" << endl;
michael@0 655
michael@0 656 symbol_order *population = new symbol_order[opt_population_size];
michael@0 657
michael@0 658 symbol_order::score_t total = 0, min = symbol_order::max_score, max = 0;
michael@0 659
michael@0 660 // Score it.
michael@0 661 symbol_order *order = population;
michael@0 662 symbol_order *limit = population + opt_population_size;
michael@0 663 for (; order < limit; ++order) {
michael@0 664 order->m_ordering = ordering;
michael@0 665 order->shuffle();
michael@0 666
michael@0 667 symbol_order::score_t score = symbol_order::compute_score(*order);
michael@0 668
michael@0 669 if (opt_debug)
michael@0 670 cerr << *order;
michael@0 671
michael@0 672 if (min > score)
michael@0 673 min = score;
michael@0 674 if (max < score)
michael@0 675 max = score;
michael@0 676
michael@0 677 total += score;
michael@0 678 }
michael@0 679
michael@0 680 if (opt_verbose) {
michael@0 681 cerr << "Initial population";
michael@0 682 cerr << ": min=" << min;
michael@0 683 cerr << ", max=" << max;
michael@0 684 cerr << " mean=" << (total / opt_population_size);
michael@0 685 cerr << endl;
michael@0 686 }
michael@0 687
michael@0 688
michael@0 689 // Run the GA.
michael@0 690 if (opt_verbose)
michael@0 691 cerr << "begininng ga" << endl;
michael@0 692
michael@0 693 symbol_order::score_t best = 0;
michael@0 694
michael@0 695 for (int generation = 1; generation <= opt_generations; ++generation) {
michael@0 696 // Create a new population.
michael@0 697 symbol_order *offspring = new symbol_order[opt_population_size];
michael@0 698
michael@0 699 symbol_order *kid = offspring;
michael@0 700 symbol_order *offspring_limit = offspring + opt_population_size;
michael@0 701 for (; kid < offspring_limit; ++kid) {
michael@0 702 // Pick parents.
michael@0 703 symbol_order *father, *mother;
michael@0 704 father = pick_parent(population, max, llrand() % total);
michael@0 705 mother = pick_parent(population, max, llrand() % total);
michael@0 706
michael@0 707 // Create a kid.
michael@0 708 kid->crossover_from(father, mother);
michael@0 709
michael@0 710 // Mutate, possibly.
michael@0 711 if (opt_mutate) {
michael@0 712 if (rand() % opt_mutate == 0)
michael@0 713 kid->mutate();
michael@0 714 }
michael@0 715 }
michael@0 716
michael@0 717 delete[] population;
michael@0 718 population = offspring;
michael@0 719
michael@0 720 // Score the new population.
michael@0 721 total = 0;
michael@0 722 min = symbol_order::max_score;
michael@0 723 max = 0;
michael@0 724
michael@0 725 symbol_order *fittest = 0;
michael@0 726
michael@0 727 limit = offspring_limit;
michael@0 728 for (order = population; order < limit; ++order) {
michael@0 729 symbol_order::score_t score = symbol_order::compute_score(*order);
michael@0 730
michael@0 731 if (opt_debug)
michael@0 732 cerr << *order;
michael@0 733
michael@0 734 if (min > score)
michael@0 735 min = score;
michael@0 736
michael@0 737 if (max < score)
michael@0 738 max = score;
michael@0 739
michael@0 740 if (best < score) {
michael@0 741 best = score;
michael@0 742 fittest = order;
michael@0 743 }
michael@0 744
michael@0 745 total += score;
michael@0 746 }
michael@0 747
michael@0 748 if (opt_verbose) {
michael@0 749 cerr << "Generation " << generation;
michael@0 750 cerr << ": min=" << min;
michael@0 751 cerr << ", max=" << max;
michael@0 752 if (fittest)
michael@0 753 cerr << "*";
michael@0 754 cerr << " mean=" << (total / opt_population_size);
michael@0 755 cerr << endl;
michael@0 756 }
michael@0 757
michael@0 758 // If we've found a new ``best'' individual, dump it.
michael@0 759 if (fittest)
michael@0 760 fittest->dump_symbols();
michael@0 761 }
michael@0 762
michael@0 763 delete[] population;
michael@0 764 return 0;
michael@0 765 }

mercurial