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;
}
|