DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (777e60ca8853)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*

  A program that computes a call histogram from runtime call
  information. It reads a list of address references (e.g., as
  computed by libcygprof.so), and uses an ELF image to map the
  addresses to functions.

 */

#include <fstream>
#include <hash_map>
#include <limits.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

#include "elf_symbol_table.h"

#define _GNU_SOURCE
#include <getopt.h>

const char *opt_exe;
int opt_tick = 0;

elf_symbol_table table;

typedef hash_map<unsigned int, unsigned int> histogram_t;
histogram_t histogram;

static struct option long_options[] = {
    { "exe",  required_argument, 0, 'e' },
    { "tick", optional_argument, 0, 't' },
    { 0,      0,                 0, 0   }
};

static void
usage(const char *name)
{
    cerr << "usage: " << name << " --exe=<image> [--tick[=count]]" << endl;
}

static void
map_addrs(int fd)
{
    // Read the binary addresses from stdin.
    unsigned int buf[128];
    ssize_t cb;

    unsigned int count = 0;
    while ((cb = read(fd, buf, sizeof buf)) > 0) {
        if (cb % sizeof buf[0])
            fprintf(stderr, "unaligned read\n");

        unsigned int *addr = buf;
        unsigned int *limit = buf + (cb / 4);

        for (; addr < limit; ++addr) {
            const Elf32_Sym *sym = table.lookup(*addr);
            if (sym)
                ++histogram[reinterpret_cast<unsigned int>(sym)];

            if (opt_tick && (++count % opt_tick == 0)) {
                cerr << ".";
                flush(cerr);
            }
        }
    }

    if (opt_tick)
        cerr << endl;
}

int
main(int argc, char *argv[])
{
    int c;
    while (1) {
        int option_index = 0;
        c = getopt_long(argc, argv, "e:t", long_options, &option_index);

        if (c < 0)
            break;

        switch (c) {
        case 'e':
            opt_exe = optarg;
            break;

        case 't':
            opt_tick = optarg ? atoi(optarg) : 1000000;
            break;

        default:
            usage(argv[0]);
            return 1;
        }
    }

    if (! opt_exe) {
        usage(argv[0]);
        return 1;
    }

    table.init(opt_exe);

    // Process addresses.
    if (optind >= argc) {
        map_addrs(STDIN_FILENO);
    }
    else {
        do {
            int fd = open(argv[optind], O_RDONLY);
            if (fd < 0) {
                perror(argv[optind]);
                return 1;
            }

            map_addrs(fd);
            close(fd);
        } while (++optind < argc);
    }
    
    // Emit the histogram.
    histogram_t::const_iterator limit = histogram.end();
    histogram_t::const_iterator i;
    for (i = histogram.begin(); i != limit; ++i) {
        const Elf32_Sym *sym = reinterpret_cast<const Elf32_Sym *>(i->first);
        cout.form("%08x %6d %2d %10d ",
                  sym->st_value,
                  sym->st_size,
                  sym->st_shndx,
                  i->second);

        cout << table.get_symbol_name(sym) << endl;
    }

    return 0;
}