]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/readprofile.c
Imported from util-linux-2.11b 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 */
29
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include "nls.h"
39
40 #define RELEASE "2.0, May 1996"
41
42 #define S_LEN 128
43
44 static char *prgname;
45
46 /* These are the defaults */
47 static char defaultmap[]="/usr/src/linux/System.map";
48 static char defaultpro[]="/proc/profile";
49 static char optstring[]="M:m:p:itvarV";
50
51 static void
52 usage(void) {
53 fprintf(stderr,
54 _("%s: Usage: \"%s [options]\n"
55 "\t -m <mapfile> (default = \"%s\")\n"
56 "\t -p <pro-file> (default = \"%s\")\n"
57 "\t -M <mult> set the profiling multiplier to <mult>\n"
58 "\t -i print only info about the sampling step\n"
59 "\t -v print verbose data\n"
60 "\t -a print all symbols, even if count is 0\n"
61 "\t -r reset all the counters (root only)\n"
62 "\t -V print version and exit\n")
63 ,prgname,prgname,defaultmap,defaultpro);
64 exit(1);
65 }
66
67 static FILE *
68 myopen(char *name, char *mode, int *flag) {
69 static char cmdline[S_LEN];
70
71 if (!strcmp(name+strlen(name)-3,".gz")) {
72 *flag=1;
73 sprintf(cmdline,"zcat %s", name);
74 return popen(cmdline,mode);
75 }
76 *flag=0;
77 return fopen(name,mode);
78 }
79
80 int
81 main (int argc, char **argv) {
82 FILE *map;
83 int proFd;
84 char *mapFile, *proFile, *mult=0;
85 unsigned long len=0, add0=0, indx=0;
86 unsigned int step;
87 unsigned int *buf, total, fn_len;
88 unsigned long fn_add, next_add; /* current and next address */
89 char fn_name[S_LEN], next_name[S_LEN]; /* current and next name */
90 char mode[8];
91 int c;
92 int optAll=0, optInfo=0, optReset=0, optVerbose=0;
93 char mapline[S_LEN];
94 int maplineno=1;
95 int popenMap; /* flag to tell if popen() has been used */
96
97 #define next (current^1)
98
99 setlocale(LC_ALL, "");
100 bindtextdomain(PACKAGE, LOCALEDIR);
101 textdomain(PACKAGE);
102
103 prgname=argv[0];
104 proFile=defaultpro;
105 mapFile=defaultmap;
106
107 while ((c=getopt(argc,argv,optstring))!=-1) {
108 switch(c) {
109 case 'm': mapFile=optarg; break;
110 case 'p': proFile=optarg; break;
111 case 'a': optAll++; break;
112 case 'i': optInfo++; break;
113 case 'M': mult=optarg; break;
114 case 'r': optReset++; break;
115 case 'v': optVerbose++; break;
116 case 'V': printf(_("%s Version %s\n"),prgname,RELEASE);
117 exit(0);
118 default: usage();
119 }
120 }
121
122 if (optReset || mult) {
123 int multiplier, fd, to_write;
124
125 /*
126 * When writing the multiplier, if the length of the write is
127 * not sizeof(int), the multiplier is not changed
128 */
129 if (mult) {
130 multiplier = strtoul(mult, 0, 10);
131 to_write = sizeof(int);
132 } else {
133 multiplier = 0;
134 to_write = 1; /* sth different from sizeof(int) */
135 }
136 /* try to become root, just in case */
137 setuid(0);
138 fd = open(defaultpro,O_WRONLY);
139 if (fd < 0) {
140 perror(defaultpro);
141 exit(1);
142 }
143 if (write(fd, &multiplier, to_write) != to_write) {
144 fprintf(stderr, "readprofile: error writing %s: %s\n",
145 defaultpro, strerror(errno));
146 exit(1);
147 }
148 close(fd);
149 exit(0);
150 }
151
152 /*
153 * Use an fd for the profiling buffer, to skip stdio overhead
154 */
155 if ( ((proFd=open(proFile,O_RDONLY)) < 0)
156 || ((int)(len=lseek(proFd,0,SEEK_END)) < 0)
157 || (lseek(proFd,0,SEEK_SET)<0) ) {
158 fprintf(stderr,"%s: %s: %s\n",prgname,proFile,strerror(errno));
159 exit(1);
160 }
161
162 if ( !(buf=malloc(len)) ) {
163 fprintf(stderr,"%s: malloc(): %s\n",prgname, strerror(errno));
164 exit(1);
165 }
166
167 if (read(proFd,buf,len) != len) {
168 fprintf(stderr,"%s: %s: %s\n",prgname,proFile,strerror(errno));
169 exit(1);
170 }
171 close(proFd);
172
173 step=buf[0];
174 if (optInfo) {
175 printf(_("Sampling_step: %i\n"),step);
176 exit(0);
177 }
178
179 total=0;
180
181 if (!(map=myopen(mapFile,"r",&popenMap))) {
182 fprintf(stderr,"%s: ",prgname);perror(mapFile);
183 exit(1);
184 }
185
186 while(fgets(mapline,S_LEN,map)) {
187 if (sscanf(mapline,"%lx %s %s",&fn_add,mode,fn_name)!=3) {
188 fprintf(stderr,_("%s: %s(%i): wrong map line\n"),
189 prgname,mapFile, maplineno);
190 exit(1);
191 }
192 if (!strcmp(fn_name,"_stext")) /* only elf works like this */ {
193 add0=fn_add;
194 break;
195 }
196 }
197
198 if (!add0) {
199 fprintf(stderr,_("%s: can't find \"_stext\" in %s\n"),
200 prgname, mapFile);
201 exit(1);
202 }
203
204 /*
205 * Main loop.
206 */
207 while(fgets(mapline,S_LEN,map)) {
208 unsigned int this=0;
209
210 if (sscanf(mapline,"%lx %s %s",&next_add,mode,next_name)!=3) {
211 fprintf(stderr,_("%s: %s(%i): wrong map line\n"),
212 prgname,mapFile, maplineno);
213 exit(1);
214 }
215
216 /* ignore any LEADING (before a '[tT]' symbol is found)
217 Absolute symbols */
218 if (*mode == 'A' && total == 0) continue;
219 if (*mode!='T' && *mode!='t') break;/* only text is profiled */
220
221 while (indx < (next_add-add0)/step)
222 this += buf[indx++];
223 total += this;
224
225 fn_len = next_add-fn_add;
226 if (fn_len && (this || optAll)) {
227 if (optVerbose)
228 printf("%08lx %-40s %6i %8.4f\n", fn_add,
229 fn_name,this,this/(double)fn_len);
230 else
231 printf("%6i %-40s %8.4f\n",
232 this,fn_name,this/(double)fn_len);
233 }
234 fn_add=next_add; strcpy(fn_name,next_name);
235 }
236 /* trailer */
237 if (optVerbose)
238 printf("%08x %-40s %6i %8.4f\n",
239 0,"total",total,total/(double)(fn_add-add0));
240 else
241 printf("%6i %-40s %8.4f\n",
242 total,_("total"),total/(double)(fn_add-add0));
243
244 popenMap ? pclose(map) : fclose(map);
245 exit(0);
246 }