]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/readprofile.c
Make the ways of using output stream consistent in usage()
[thirdparty/util-linux.git] / sys-utils / readprofile.c
CommitLineData
6dbe3af9
KZ
1/*
2 * readprofile.c - used to read /proc/profile
3 *
fd6b7a7f 4 * Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it)
6dbe3af9
KZ
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
7cebf0bb
SK
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6dbe3af9
KZ
19 */
20
7eda085c 21/*
b50945d4 22 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c 23 * - added Native Language Support
eb63b9b8
KZ
24 * 1999-09-01 Stephane Eranian <eranian@cello.hpl.hp.com>
25 * - 64bit clean patch
c07ebfa1
KZ
26 * 3Feb2001 Andrew Morton <andrewm@uow.edu.au>
27 * - -M option to write profile multiplier.
612721db
KZ
28 * 2001-11-07 Werner Almesberger <wa@almesberger.net>
29 * - byte order auto-detection and -n option
30 * 2001-11-09 Werner Almesberger <wa@almesberger.net>
31 * - skip step size (index 0)
1d4ad1de
KZ
32 * 2002-03-09 John Levon <moz@compsoc.man.ac.uk>
33 * - make maplineno do something
df1dddf9
KZ
34 * 2002-11-28 Mads Martin Joergensen +
35 * - also try /boot/System.map-`uname -r`
36 * 2003-04-09 Werner Almesberger <wa@almesberger.net>
37 * - fixed off-by eight error and improved heuristics in byte order detection
c129767e
KZ
38 * 2003-08-12 Nikita Danilov <Nikita@Namesys.COM>
39 * - added -s option; example of use:
40 * "readprofile -s -m /boot/System.map-test | grep __d_lookup | sort -n -k3"
7eda085c
KZ
41 */
42
fd6b7a7f 43#include <errno.h>
df1dddf9 44#include <fcntl.h>
a3f0ea51
SK
45#include <getopt.h>
46#include <stdio.h>
6dbe3af9 47#include <stdlib.h>
6dbe3af9 48#include <string.h>
fd6b7a7f 49#include <sys/stat.h>
a3f0ea51 50#include <sys/types.h>
df1dddf9 51#include <sys/utsname.h>
a3f0ea51 52#include <unistd.h>
2ab428f6 53
3e5e56eb
KZ
54#include "c.h"
55#include "strutils.h"
7eda085c 56#include "nls.h"
a3f0ea51 57#include "xalloc.h"
efb8854f 58#include "closestream.h"
6dbe3af9 59
6dbe3af9
KZ
60#define S_LEN 128
61
fd6b7a7f 62/* These are the defaults */
b22550fa 63static char defaultmap[]="/boot/System.map";
6dbe3af9 64static char defaultpro[]="/proc/profile";
6dbe3af9 65
a3f0ea51
SK
66static FILE *myopen(char *name, char *mode, int *flag)
67{
e8f26419 68 int len = strlen(name);
c07ebfa1 69
a3f0ea51 70 if (!strcmp(name + len - 3, ".gz")) {
e8f26419 71 FILE *res;
a3f0ea51 72 char *cmdline = xmalloc(len + 6);
914966e9 73 snprintf(cmdline, len + 6, "zcat %s", name);
a3f0ea51 74 res = popen(cmdline, mode);
e8f26419
KZ
75 free(cmdline);
76 *flag = 1;
77 return res;
c07ebfa1 78 }
e8f26419 79 *flag = 0;
a3f0ea51 80 return fopen(name, mode);
6dbe3af9
KZ
81}
82
df1dddf9
KZ
83#ifndef BOOT_SYSTEM_MAP
84#define BOOT_SYSTEM_MAP "/boot/System.map-"
85#endif
a3f0ea51
SK
86
87static char *boot_uname_r_str(void)
88{
df1dddf9
KZ
89 struct utsname uname_info;
90 char *s;
91 size_t len;
92
93 if (uname(&uname_info))
94 return "";
95 len = strlen(BOOT_SYSTEM_MAP) + strlen(uname_info.release) + 1;
96 s = xmalloc(len);
97 strcpy(s, BOOT_SYSTEM_MAP);
98 strcat(s, uname_info.release);
99 return s;
100}
101
86be6a32 102static void __attribute__((__noreturn__)) usage(void)
a3f0ea51 103{
86be6a32 104 FILE *out = stdout;
443f7313
SK
105 fputs(USAGE_HEADER, out);
106 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
443f7313 107
451dbcfa
BS
108 fputs(USAGE_SEPARATOR, out);
109 fputs(_("Display kernel profiling information.\n"), out);
110
111 fputs(USAGE_OPTIONS, out);
443f7313
SK
112 fprintf(out,
113 _(" -m, --mapfile <mapfile> (defaults: \"%s\" and\n"), defaultmap);
114 fprintf(out,
115 _(" \"%s\")\n"), boot_uname_r_str());
116 fprintf(out,
117 _(" -p, --profile <pro-file> (default: \"%s\")\n"), defaultpro);
118 fputs(_(" -M, --multiplier <mult> set the profiling multiplier to <mult>\n"), out);
119 fputs(_(" -i, --info print only info about the sampling step\n"), out);
120 fputs(_(" -v, --verbose print verbose data\n"), out);
121 fputs(_(" -a, --all print all symbols, even if count is 0\n"), out);
122 fputs(_(" -b, --histbin print individual histogram-bin counts\n"), out);
123 fputs(_(" -s, --counters print individual counters within functions\n"), out);
124 fputs(_(" -r, --reset reset all the counters (root only)\n"), out);
125 fputs(_(" -n, --no-auto disable byte order auto-detection\n"), out);
126 fputs(USAGE_SEPARATOR, out);
bad4c729
MY
127 fprintf(out, USAGE_HELP_OPTIONS(27));
128 fprintf(out, USAGE_MAN_TAIL("readprofile(8)"));
86be6a32 129 exit(EXIT_SUCCESS);
df1dddf9
KZ
130}
131
a3f0ea51
SK
132int main(int argc, char **argv)
133{
c07ebfa1 134 FILE *map;
3e5e56eb
KZ
135 int proFd, has_mult = 0, multiplier = 0;
136 char *mapFile, *proFile;
a3f0ea51
SK
137 size_t len = 0, indx = 1;
138 unsigned long long add0 = 0;
c07ebfa1
KZ
139 unsigned int step;
140 unsigned int *buf, total, fn_len;
4813a521 141 unsigned long long fn_add = 0, next_add; /* current and next address */
a3f0ea51 142 char fn_name[S_LEN], next_name[S_LEN]; /* current and next name */
c07ebfa1
KZ
143 char mode[8];
144 int c;
33d18dc4 145 ssize_t rc;
a3f0ea51
SK
146 int optAll = 0, optInfo = 0, optReset = 0, optVerbose = 0, optNative = 0;
147 int optBins = 0, optSub = 0;
c07ebfa1 148 char mapline[S_LEN];
a3f0ea51
SK
149 int maplineno = 1;
150 int popenMap; /* flag to tell if popen() has been used */
f0c8eda1 151 int header_printed;
4f62b0b1 152 double rep = 0;
6dbe3af9 153
443f7313
SK
154 static const struct option longopts[] = {
155 {"mapfile", required_argument, NULL, 'm'},
156 {"profile", required_argument, NULL, 'p'},
157 {"multiplier", required_argument, NULL, 'M'},
158 {"info", no_argument, NULL, 'i'},
159 {"verbose", no_argument, NULL, 'v'},
160 {"all", no_argument, NULL, 'a'},
161 {"histbin", no_argument, NULL, 'b'},
162 {"counters", no_argument, NULL, 's'},
9b80bef6 163 {"reset", no_argument, NULL, 'r'},
443f7313
SK
164 {"no-auto", no_argument, NULL, 'n'},
165 {"version", no_argument, NULL, 'V'},
166 {"help", no_argument, NULL, 'h'},
87918040 167 {NULL, 0, NULL, 0}
443f7313
SK
168 };
169
6dbe3af9
KZ
170#define next (current^1)
171
c07ebfa1
KZ
172 setlocale(LC_ALL, "");
173 bindtextdomain(PACKAGE, LOCALEDIR);
174 textdomain(PACKAGE);
2c308875 175 close_stdout_atexit();
c07ebfa1 176
df1dddf9
KZ
177 proFile = defaultpro;
178 mapFile = defaultmap;
c07ebfa1 179
cda9acbe 180 while ((c = getopt_long(argc, argv, "m:p:M:ivabsrnVh", longopts, NULL)) != -1) {
a3f0ea51 181 switch (c) {
df1dddf9
KZ
182 case 'm':
183 mapFile = optarg;
184 break;
185 case 'n':
186 optNative++;
187 break;
188 case 'p':
189 proFile = optarg;
190 break;
191 case 'a':
192 optAll++;
193 break;
194 case 'b':
195 optBins++;
196 break;
c129767e
KZ
197 case 's':
198 optSub++;
199 break;
df1dddf9
KZ
200 case 'i':
201 optInfo++;
202 break;
203 case 'M':
3e5e56eb
KZ
204 multiplier = strtol_or_err(optarg, _("failed to parse multiplier"));
205 has_mult = 1;
df1dddf9
KZ
206 break;
207 case 'r':
208 optReset++;
209 break;
210 case 'v':
211 optVerbose++;
212 break;
2c308875 213
df1dddf9 214 case 'V':
2c308875 215 print_version(EXIT_SUCCESS);
443f7313 216 case 'h':
86be6a32 217 usage();
df1dddf9 218 default:
677ec86c 219 errtryhelp(EXIT_FAILURE);
c07ebfa1
KZ
220 }
221 }
222
3e5e56eb
KZ
223 if (optReset || has_mult) {
224 int fd, to_write;
c07ebfa1 225
a3f0ea51
SK
226 /* When writing the multiplier, if the length of the
227 * write is not sizeof(int), the multiplier is not
228 * changed. */
3e5e56eb 229 if (has_mult) {
c07ebfa1
KZ
230 to_write = sizeof(int);
231 } else {
232 multiplier = 0;
a3f0ea51
SK
233 /* sth different from sizeof(int) */
234 to_write = 1;
c07ebfa1
KZ
235 }
236 /* try to become root, just in case */
8f3b568c 237 ignore_result( setuid(0) );
a3f0ea51 238 fd = open(defaultpro, O_WRONLY);
c416814a
SK
239 if (fd < 0)
240 err(EXIT_FAILURE, "%s", defaultpro);
241 if (write(fd, &multiplier, to_write) != to_write)
242 err(EXIT_FAILURE, _("error writing %s"), defaultpro);
c07ebfa1 243 close(fd);
c416814a 244 exit(EXIT_SUCCESS);
c07ebfa1
KZ
245 }
246
a3f0ea51
SK
247 /* Use an fd for the profiling buffer, to skip stdio overhead */
248 if (((proFd = open(proFile, O_RDONLY)) < 0)
249 || ((int)(len = lseek(proFd, 0, SEEK_END)) < 0)
250 || (lseek(proFd, 0, SEEK_SET) < 0))
c416814a 251 err(EXIT_FAILURE, "%s", proFile);
cae9283a
SK
252 if (!len)
253 errx(EXIT_FAILURE, "%s: %s", proFile, _("input file is empty"));
c07ebfa1 254
2ab428f6 255 buf = xmalloc(len);
c07ebfa1 256
a3f0ea51 257 rc = read(proFd, buf, len);
c416814a 258 if (rc < 0 || (size_t) rc != len)
a3f0ea51 259 err(EXIT_FAILURE, "%s", proFile);
c07ebfa1
KZ
260 close(proFd);
261
612721db 262 if (!optNative) {
a3f0ea51
SK
263 int entries = len / sizeof(*buf);
264 int big = 0, small = 0;
612721db 265 unsigned *p;
33d18dc4 266 size_t i;
612721db 267
a3f0ea51 268 for (p = buf + 1; p < buf + entries; p++) {
517debc3 269 if (*p & ~0U << ((unsigned) sizeof(*buf) * 4U))
df1dddf9 270 big++;
517debc3 271 if (*p & ((1U << ((unsigned) sizeof(*buf) * 4U)) - 1U))
df1dddf9
KZ
272 small++;
273 }
612721db 274 if (big > small) {
c416814a
SK
275 warnx(_("Assuming reversed byte order. "
276 "Use -n to force native byte order."));
a3f0ea51
SK
277 for (p = buf; p < buf + entries; p++)
278 for (i = 0; i < sizeof(*buf) / 2; i++) {
279 unsigned char *b = (unsigned char *)p;
612721db 280 unsigned char tmp;
612721db 281 tmp = b[i];
a3f0ea51
SK
282 b[i] = b[sizeof(*buf) - i - 1];
283 b[sizeof(*buf) - i - 1] = tmp;
612721db
KZ
284 }
285 }
286 }
287
df1dddf9 288 step = buf[0];
c07ebfa1 289 if (optInfo) {
e3ca1312 290 printf(_("Sampling_step: %u\n"), step);
c416814a 291 exit(EXIT_SUCCESS);
a3f0ea51 292 }
c07ebfa1 293
df1dddf9 294 total = 0;
c07ebfa1 295
df1dddf9
KZ
296 map = myopen(mapFile, "r", &popenMap);
297 if (map == NULL && mapFile == defaultmap) {
298 mapFile = boot_uname_r_str();
299 map = myopen(mapFile, "r", &popenMap);
300 }
c416814a
SK
301 if (map == NULL)
302 err(EXIT_FAILURE, "%s", mapFile);
c07ebfa1 303
a3f0ea51 304 while (fgets(mapline, S_LEN, map)) {
01b63fcc 305 if (sscanf(mapline, "%llx %7[^\n ] %127[^\n ]", &fn_add, mode, fn_name) != 3)
c416814a
SK
306 errx(EXIT_FAILURE, _("%s(%i): wrong map line"), mapFile,
307 maplineno);
db94975b 308 /* only elf works like this */
a3f0ea51 309 if (!strcmp(fn_name, "_stext") || !strcmp(fn_name, "__stext")) {
1d4ad1de 310 add0 = fn_add;
c07ebfa1
KZ
311 break;
312 }
1d4ad1de 313 maplineno++;
c07ebfa1
KZ
314 }
315
c416814a
SK
316 if (!add0)
317 errx(EXIT_FAILURE, _("can't find \"_stext\" in %s"), mapFile);
c07ebfa1
KZ
318
319 /*
320 * Main loop.
321 */
a3f0ea51
SK
322 while (fgets(mapline, S_LEN, map)) {
323 unsigned int this = 0;
5a3009ca 324 int done = 0;
c07ebfa1 325
01b63fcc 326 if (sscanf(mapline, "%llx %7[^\n ] %127[^\n ]", &next_add, mode, next_name) != 3)
c416814a
SK
327 errx(EXIT_FAILURE, _("%s(%i): wrong map line"), mapFile,
328 maplineno);
f0c8eda1 329 header_printed = 0;
c07ebfa1 330
5a3009ca
MK
331 /* the kernel only profiles up to _etext */
332 if (!strcmp(next_name, "_etext") ||
333 !strcmp(next_name, "__etext"))
334 done = 1;
335 else {
a3f0ea51
SK
336 /* ignore any LEADING (before a '[tT]' symbol
337 * is found) Absolute symbols and __init_end
338 * because some architectures place it before
339 * .text section */
236faa7e
PYC
340 if ((*mode == 'A' || *mode == '?')
341 && (total == 0 || !strcmp(next_name, "__init_end")))
5a3009ca
MK
342 continue;
343 if (*mode != 'T' && *mode != 't' &&
344 *mode != 'W' && *mode != 'w')
345 break; /* only text is profiled */
346 }
c07ebfa1 347
c416814a
SK
348 if (indx >= len / sizeof(*buf))
349 errx(EXIT_FAILURE,
350 _("profile address out of range. Wrong map file?"));
364cda48 351
4f62b0b1 352 while (step > 0 && indx < (next_add - add0) / step) {
f0c8eda1
KZ
353 if (optBins && (buf[indx] || optAll)) {
354 if (!header_printed) {
a3f0ea51 355 printf("%s:\n", fn_name);
f0c8eda1
KZ
356 header_printed = 1;
357 }
a3f0ea51
SK
358 printf("\t%llx\t%u\n", (indx - 1) * step + add0,
359 buf[indx]);
f0c8eda1 360 }
c07ebfa1 361 this += buf[indx++];
f0c8eda1 362 }
c07ebfa1
KZ
363 total += this;
364
f0c8eda1
KZ
365 if (optBins) {
366 if (optVerbose || this > 0)
a3f0ea51 367 printf(" total\t\t\t\t%u\n", this);
c129767e 368 } else if ((this || optAll) &&
a3f0ea51 369 (fn_len = next_add - fn_add) != 0) {
c129767e 370 if (optVerbose)
e3ca1312 371 printf("%016llx %-40s %6u %8.4f\n", fn_add,
a3f0ea51 372 fn_name, this, this / (double)fn_len);
c129767e 373 else
e3ca1312 374 printf("%6u %-40s %8.4f\n",
a3f0ea51 375 this, fn_name, this / (double)fn_len);
4f62b0b1 376 if (optSub && step > 0) {
c129767e
KZ
377 unsigned long long scan;
378
a3f0ea51
SK
379 for (scan = (fn_add - add0) / step + 1;
380 scan < (next_add - add0) / step;
381 scan++) {
c129767e 382 unsigned long long addr;
a3f0ea51 383 addr = (scan - 1) * step + add0;
c129767e
KZ
384 printf("\t%#llx\t%s+%#llx\t%u\n",
385 addr, fn_name, addr - fn_add,
386 buf[scan]);
387 }
f0c8eda1 388 }
c07ebfa1 389 }
c129767e
KZ
390
391 fn_add = next_add;
a3f0ea51 392 strcpy(fn_name, next_name);
1d4ad1de
KZ
393
394 maplineno++;
5a3009ca
MK
395 if (done)
396 break;
c07ebfa1 397 }
d162fcb5
KZ
398
399 /* clock ticks, out of kernel text - probably modules */
e3ca1312 400 printf("%6u %s\n", buf[len / sizeof(*buf) - 1], "*unknown*");
d162fcb5 401
4f62b0b1
KZ
402 if (fn_add > add0)
403 rep = total / (double)(fn_add - add0);
404
c07ebfa1
KZ
405 /* trailer */
406 if (optVerbose)
e3ca1312 407 printf("%016x %-40s %6u %8.4f\n",
4f62b0b1 408 0, "total", total, rep);
c07ebfa1 409 else
e3ca1312 410 printf("%6u %-40s %8.4f\n",
4f62b0b1 411 total, _("total"), rep);
a3f0ea51 412
c07ebfa1 413 popenMap ? pclose(map) : fclose(map);
c416814a 414 exit(EXIT_SUCCESS);
6dbe3af9 415}