]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/readprofile.c
Imported from util-linux-2.11n tarball.
[thirdparty/util-linux.git] / sys-utils / readprofile.c
1 /*
2 * readprofile.c - used to read /proc/profile
3 *
4 * Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it)
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 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
23 * - added Native Language Support
24 * 1999-09-01 Stephane Eranian <eranian@cello.hpl.hp.com>
25 * - 64bit clean patch
26 * 3Feb2001 Andrew Morton <andrewm@uow.edu.au>
27 * - -M option to write profile multiplier.
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)
32 */
33
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include "nls.h"
43
44 #define RELEASE "2.0, May 1996"
45
46 #define S_LEN 128
47
48 static char *prgname;
49
50 /* These are the defaults */
51 static char defaultmap[]="/usr/src/linux/System.map";
52 static char defaultpro[]="/proc/profile";
53 static char optstring[]="M:m:np:itvarV";
54
55 static void
56 usage(void) {
57 fprintf(stderr,
58 _("%s: Usage: \"%s [options]\n"
59 "\t -m <mapfile> (default = \"%s\")\n"
60 "\t -p <pro-file> (default = \"%s\")\n"
61 "\t -M <mult> set the profiling multiplier to <mult>\n"
62 "\t -i print only info about the sampling step\n"
63 "\t -v print verbose data\n"
64 "\t -a print all symbols, even if count is 0\n"
65 "\t -r reset all the counters (root only)\n"
66 "\t -n disable byte order auto-detection\n"
67 "\t -V print version and exit\n")
68 ,prgname,prgname,defaultmap,defaultpro);
69 exit(1);
70 }
71
72 static void *
73 xmalloc (size_t size) {
74 void *t;
75
76 if (size == 0)
77 return NULL;
78
79 t = malloc (size);
80 if (t == NULL) {
81 fprintf(stderr, _("out of memory"));
82 exit(1);
83 }
84
85 return t;
86 }
87
88 static FILE *
89 myopen(char *name, char *mode, int *flag) {
90 int len = strlen(name);
91
92 if (!strcmp(name+len-3,".gz")) {
93 FILE *res;
94 char *cmdline = xmalloc(len+6);
95 sprintf(cmdline, "zcat %s", name);
96 res = popen(cmdline,mode);
97 free(cmdline);
98 *flag = 1;
99 return res;
100 }
101 *flag = 0;
102 return fopen(name,mode);
103 }
104
105 int
106 main (int argc, char **argv) {
107 FILE *map;
108 int proFd;
109 char *mapFile, *proFile, *mult=0;
110 unsigned long len=0, add0=0, indx=1;
111 unsigned int step;
112 unsigned int *buf, total, fn_len;
113 unsigned long fn_add, next_add; /* current and next address */
114 char fn_name[S_LEN], next_name[S_LEN]; /* current and next name */
115 char mode[8];
116 int c;
117 int optAll=0, optInfo=0, optReset=0, optVerbose=0, optNative=0;
118 char mapline[S_LEN];
119 int maplineno=1;
120 int popenMap; /* flag to tell if popen() has been used */
121
122 #define next (current^1)
123
124 setlocale(LC_ALL, "");
125 bindtextdomain(PACKAGE, LOCALEDIR);
126 textdomain(PACKAGE);
127
128 prgname=argv[0];
129 proFile=defaultpro;
130 mapFile=defaultmap;
131
132 while ((c=getopt(argc,argv,optstring))!=-1) {
133 switch(c) {
134 case 'm': mapFile=optarg; break;
135 case 'n': optNative++; break;
136 case 'p': proFile=optarg; break;
137 case 'a': optAll++; break;
138 case 'i': optInfo++; break;
139 case 'M': mult=optarg; break;
140 case 'r': optReset++; break;
141 case 'v': optVerbose++; break;
142 case 'V': printf(_("%s Version %s\n"),prgname,RELEASE);
143 exit(0);
144 default: usage();
145 }
146 }
147
148 if (optReset || mult) {
149 int multiplier, fd, to_write;
150
151 /*
152 * When writing the multiplier, if the length of the write is
153 * not sizeof(int), the multiplier is not changed
154 */
155 if (mult) {
156 multiplier = strtoul(mult, 0, 10);
157 to_write = sizeof(int);
158 } else {
159 multiplier = 0;
160 to_write = 1; /* sth different from sizeof(int) */
161 }
162 /* try to become root, just in case */
163 setuid(0);
164 fd = open(defaultpro,O_WRONLY);
165 if (fd < 0) {
166 perror(defaultpro);
167 exit(1);
168 }
169 if (write(fd, &multiplier, to_write) != to_write) {
170 fprintf(stderr, "readprofile: error writing %s: %s\n",
171 defaultpro, strerror(errno));
172 exit(1);
173 }
174 close(fd);
175 exit(0);
176 }
177
178 /*
179 * Use an fd for the profiling buffer, to skip stdio overhead
180 */
181 if ( ((proFd=open(proFile,O_RDONLY)) < 0)
182 || ((int)(len=lseek(proFd,0,SEEK_END)) < 0)
183 || (lseek(proFd,0,SEEK_SET)<0) ) {
184 fprintf(stderr,"%s: %s: %s\n",prgname,proFile,strerror(errno));
185 exit(1);
186 }
187
188 if ( !(buf=malloc(len)) ) {
189 fprintf(stderr,"%s: malloc(): %s\n",prgname, strerror(errno));
190 exit(1);
191 }
192
193 if (read(proFd,buf,len) != len) {
194 fprintf(stderr,"%s: %s: %s\n",prgname,proFile,strerror(errno));
195 exit(1);
196 }
197 close(proFd);
198
199 if (!optNative) {
200 int entries = len/sizeof(*buf);
201 int big = 0,small = 0,i;
202 unsigned *p;
203
204 for (p = buf+1; p < buf+entries; p++)
205 if (*p) {
206 if (*p >= 1 << (sizeof(*buf)/2)) big++;
207 else small++;
208 }
209 if (big > small) {
210 fprintf(stderr,"Assuming reversed byte order. "
211 "Use -n to force native byte order.\n");
212 for (p = buf; p < buf+entries; p++)
213 for (i = 0; i < sizeof(*buf)/2; i++) {
214 unsigned char *b = (unsigned char *) p;
215 unsigned char tmp;
216
217 tmp = b[i];
218 b[i] = b[sizeof(*buf)-i-1];
219 b[sizeof(*buf)-i-1] = tmp;
220 }
221 }
222 }
223
224 step=buf[0];
225 if (optInfo) {
226 printf(_("Sampling_step: %i\n"),step);
227 exit(0);
228 }
229
230 total=0;
231
232 if (!(map=myopen(mapFile,"r",&popenMap))) {
233 fprintf(stderr,"%s: ",prgname);perror(mapFile);
234 exit(1);
235 }
236
237 while(fgets(mapline,S_LEN,map)) {
238 if (sscanf(mapline,"%lx %s %s",&fn_add,mode,fn_name)!=3) {
239 fprintf(stderr,_("%s: %s(%i): wrong map line\n"),
240 prgname,mapFile, maplineno);
241 exit(1);
242 }
243 if (!strcmp(fn_name,"_stext")) /* only elf works like this */ {
244 add0=fn_add;
245 break;
246 }
247 }
248
249 if (!add0) {
250 fprintf(stderr,_("%s: can't find \"_stext\" in %s\n"),
251 prgname, mapFile);
252 exit(1);
253 }
254
255 /*
256 * Main loop.
257 */
258 while(fgets(mapline,S_LEN,map)) {
259 unsigned int this=0;
260
261 if (sscanf(mapline,"%lx %s %s",&next_add,mode,next_name)!=3) {
262 fprintf(stderr,_("%s: %s(%i): wrong map line\n"),
263 prgname,mapFile, maplineno);
264 exit(1);
265 }
266
267 /* ignore any LEADING (before a '[tT]' symbol is found)
268 Absolute symbols */
269 if (*mode == 'A' && total == 0) continue;
270 if (*mode!='T' && *mode!='t') break;/* only text is profiled */
271
272 if (indx >= len / sizeof(*buf)) {
273 fprintf(stderr, _("%s: profile address out of range. "
274 "Wrong map file?\n"), prgname);
275 exit(1);
276 }
277
278 while (indx < (next_add-add0)/step)
279 this += buf[indx++];
280 total += this;
281
282 fn_len = next_add-fn_add;
283 if (fn_len && (this || optAll)) {
284 if (optVerbose)
285 printf("%08lx %-40s %6i %8.4f\n", fn_add,
286 fn_name,this,this/(double)fn_len);
287 else
288 printf("%6i %-40s %8.4f\n",
289 this,fn_name,this/(double)fn_len);
290 }
291 fn_add=next_add; strcpy(fn_name,next_name);
292 }
293 /* trailer */
294 if (optVerbose)
295 printf("%08x %-40s %6i %8.4f\n",
296 0,"total",total,total/(double)(fn_add-add0));
297 else
298 printf("%6i %-40s %8.4f\n",
299 total,_("total"),total/(double)(fn_add-add0));
300
301 popenMap ? pclose(map) : fclose(map);
302 exit(0);
303 }