"Fossies" - the Fresh Open Source Software Archive 
Member "FunctionCheck-3.2.0/src/libfc/fc_check.c" (29 May 2012, 13813 Bytes) of package /linux/privat/old/FunctionCheck-3.2.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * FunctionCheck profiler
3 * (C) Copyright 2000-2012 Yannick Perret
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #define __USE_GNU
25 #include <link.h>
26 #ifndef FC_NO_DLFCN
27 #include <dlfcn.h>
28 #endif
29 #ifndef FC_NO_THREAD
30 #include <pthread.h>
31 #endif
32
33 #include "fc_global.h"
34 #include "fc_ressources.h"
35 #include "fc_tools.h"
36 #include "fc_com.h"
37 #include "fc_memory.h"
38
39 /** IPC shared memory id **/
40 unsigned int fc_shared_memory_id = 0;
41
42 /** the initial number of dynamic libraries sent to the manager **/
43 int fc_initial_libraries = 0;
44
45 /** profiling mode (used by _fini) **/
46 static int fc_local_mode = 0;
47
48 /* help: print a reminder for available env. variables */
49 void fc_help(void)
50 {
51 fc_message("%s V%s by Y.Perret", FC_PACKAGE, FC_VERSION);
52 fc_message("Available environment variables are:");
53 fc_message("FC_HELP : this message");
54 fc_message("FC_QUIET | FC_NO_VERBOSE : disable messages");
55 fc_message("FC_BUFFER_SIZE : set the number of elements in FIFO buffer");
56 fc_message("FC_STACK_SIZE : set the default stack size");
57 fc_message("FC_FUNCTION_SIZE : set the size of functions table");
58 fc_message("FC_GRAPH_SIZE : set the call-graph default size");
59 fc_message("FC_MEMORY_SIZE : set the memory-table default size");
60 fc_message("FC_TIME_MODE : time unit used (tsc|ext|cpu|sys)");
61 fc_message("FC_DUMP_NAME : name for profile data file");
62 fc_message("FC_DUMP_PATH : path for profile data file");
63 fc_message("FC_NO_FORK : switch to single-process mode");
64 fc_message("FC_ALLOW_THREAD : switch to thread-only program");
65 fc_message("FC_USE_PID : always add PID to profile data file");
66 fc_message("FC_DEBUG : switch on debug mode");
67 fc_message("FC_MEMORY : enable memory profiling");
68 fc_message("FC_MEMORY_STACK : set the call-stack size to store");
69 }
70
71 /* check if the given number is a power of 2. if not,
72 set it to the first higher power of 2 */
73 void fc_check_power(int *nb)
74 {
75 int n, i;
76
77 n = 2;
78 for (i = 1; (i < 31) && (n <= *nb); i++)
79 {
80 if (n == *nb)
81 return; /* ok */
82 n *= 2;
83 }
84 /* no match. set nb to n */
85 *nb = n;
86 }
87
88 /** redirections for important functions **/
89
90 /* dlfnc familly */
91
92 /* redirection of the dlopen */
93 void *fc_redirect_dlopen(const char *filename, int flag)
94 {
95 void *result;
96
97 /* call dlopen */
98 #ifdef FC_NO_DLFCN
99 fc_message("'dlopen' redirected to libfc, but libfc was not")
100 fc_message(" compiled with 'dlfcn.h' available. Your 'dlopen'");
101 fc_message(" command is dropped! Try to reinstall libfc.");
102 result = NULL;
103 #else
104 result = dlopen(filename, flag);
105 #endif
106
107 /* if needed, send the result */
108 if (result != NULL)
109 fc_com_dlopen(result, filename, flag);
110
111 return (result);
112 }
113
114 /* redirection of the dlclose */
115 int fc_redirect_dlclose(void *handle)
116 {
117 int ret;
118
119 /* call dlclose */
120 #ifdef FC_NO_DLFCN
121 fc_message("'dlclose' redirected to libfc, but libfc was not")
122 fc_message(" compiled with 'dlfcn.h' available. Your 'dlclose'");
123 fc_message(" command is dropped! Try to reinstall libfc.");
124 ret = 0;
125 #else
126 ret = dlclose(handle);
127 /* send the command */
128 fc_com_dlclose(handle);
129 #endif
130
131 return (ret);
132 }
133
134 /* redirection of the dlsym */
135 void *fc_redirect_dlsym(void *handle, char *symbol)
136 {
137 void *result;
138
139 /* call dlsym */
140 #ifdef FC_NO_DLFCN
141 fc_message("'dlsym' redirected to libfc, but libfc was not")
142 fc_message(" compiled with 'dlfcn.h' available. Your 'dlsym'");
143 fc_message(" command is dropped! Try to reinstall libfc.");
144 result = NULL;
145 #else
146 result = dlsym(handle, symbol);
147 #endif
148
149 /* if needed, send the result */
150 if (result != NULL)
151 fc_com_dlsym(result, handle, symbol);
152
153 return (result);
154 }
155
156 /* redirection of fork */
157 pid_t fc_redirect_fork(void)
158 {
159 pid_t ret;
160 pid_t pid;
161
162 pid = getpid();
163 /* call fork */
164 ret = fork();
165
166 if (ret == 0)
167 {/* the child */
168 /* send a 'parent' message. */
169 fc_com_parent(pid);
170 }
171 else
172 if (ret > 0)
173 {/* the parent */
174 /* no message here because the context for the child
175 would be created immediatly, and so the starting
176 time for it would be a long time before the real
177 start of the child (due to child creation delay)
178 the information is sent by the child itself with the
179 'parent' message, indicating the _real_ start time */
180 /*fc_com_fork((int)ret);*/
181 }
182
183 return (ret);
184 }
185
186 /* redirection of pthread_create */
187 #ifndef FC_NO_THREAD
188
189 int fc_redirect_pthread_create(pthread_t *thread, pthread_attr_t *attr,
190 void *(*start_routine)(void *), void *arg)
191 {
192 int ret;
193
194 /* call pthread_create */
195 ret = pthread_create(thread, attr, start_routine, arg);
196
197 /* on success, transmit info */
198 if (ret == 0)
199 fc_com_thread(*thread);
200
201 return (ret);
202 }
203
204 #else
205
206 int fc_redirect_pthread_create(int *thread, void *attr,
207 void *(*start_routine)(void *), void *arg)
208 {
209 return (1);
210 }
211
212 #endif // FC_NO_THREAD
213
214 /* called at each begin of profiled function */
215 void __cyg_profile_func_enter(void *this_fn, void *call_site)
216 {
217 fc_com_enter(this_fn, call_site);
218 }
219
220 /* called at each end of profiled function */
221 void __cyg_profile_func_exit(void *this_fn, void *call_site)
222 {
223 fc_com_exit(this_fn, call_site);
224 }
225
226 static int dl_phdr_callback(
227 struct dl_phdr_info* info,
228 size_t size,
229 void* data)
230 {
231 FC_LDYN ldyn;
232
233 if (info->dlpi_addr)
234 {
235 ldyn.addr = (void*) info->dlpi_addr;
236 ldyn.name[0] = '\0';
237 /* print dummy lib to keep the output format: address lib */
238 if (info->dlpi_name[0])
239 strcat(ldyn.name, info->dlpi_name);
240 else
241 strcpy(ldyn.name, "<UNKNOWN_LIB>");
242 fc_com_write_lib(&ldyn);
243 fc_initial_libraries++;
244 }
245
246 return 0;
247 }
248
249 /* called at the real begin of the profiled program */
250 void __attribute__((constructor)) _init()
251 {
252 int mode, tmode, from_rc;
253 int fc_buffer_size = 128 * 1024;
254 int fc_stack_size = 1024;
255 int fc_graph_size = 512;
256 int fc_memory_size = 512;
257 int fc_function_size = 64 * 1024;
258 char fc_dump_path[64] = "./";
259 char fc_dump_name[64] = FC_DUMP_FILE;
260 #if defined (__GNUC__) && (defined (__i386__) || defined (__x86_64__))
261 char fc_time_mode[64] = "tsc";
262 #else
263 char fc_time_mode[64] = "ext";
264 #endif
265 int fc_verbose_mode = 1;
266 int fc_debug_mode = 0;
267 int fc_use_pid = 0;
268 int fc_no_fork = 1;
269 int fc_no_thread = 1;
270 int use_memory = 0;
271 int memory_stack = 4;
272 FC_INIT init;
273 /* special options */
274 int give_help = 0;
275
276 FC_LDYN ldyn;
277
278 /* set the profiler name for messages */
279 fc_set_message_name(FC_PROFILER_NAME);
280 fc_set_message_mode(fc_verbose_mode);
281
282 /* read ressource file */
283 from_rc = fc_read_ressources();
284
285 /* first get the env state in order to get activated options */
286 if (!fc_read_env(&fc_buffer_size, &fc_stack_size,
287 &fc_function_size, &fc_graph_size,
288 &fc_memory_size, fc_dump_path,
289 fc_dump_name, fc_time_mode,
290 &fc_verbose_mode, &fc_use_pid,
291 &fc_no_fork, &fc_no_thread,
292 &fc_debug_mode, &give_help,
293 &use_memory, &memory_stack))
294 {
295 /* error ! */
296 fc_message("warning: cannot read env state. starting in default mode.");
297 }
298
299 /* special */
300 if (give_help)
301 {
302 fc_help();
303 exit(FC_ERR_OK);
304 }
305
306 fc_set_message_mode(fc_verbose_mode);
307 fc_set_debug_mode(fc_debug_mode);
308 fc_debug("env readed");
309
310 /* compute the mode */
311 fc_debug("no_fork=%d, no_thread=%d", fc_no_fork, fc_no_thread);
312 if (fc_no_fork && fc_no_thread)
313 mode = FC_MODE_SINGLE;
314 else
315 if (!fc_no_thread)
316 {
317 if (!fc_allow_thread_hard)
318 {
319 fc_message("warning: %s was compiled without threads", FC_PACKAGE);
320 fc_message(" allowed. Switching to 'fork' mode.");
321 mode = FC_MODE_FORK;
322 }
323 else
324 {
325 mode = FC_MODE_THREAD;
326 }
327 }
328 else
329 mode = FC_MODE_FORK;
330
331 fc_debug("running mode is %d", mode);
332
333 /* init the time mode */
334 tmode = fc_set_time_type(fc_time_mode);
335 fc_debug("time mode is '%s' (%d)", fc_time_mode, tmode);
336
337 /* init the time reference */
338 fc_init_time();
339
340 /* init the com process */
341 fc_com_init(mode, fc_buffer_size, &fc_shared_memory_id);
342
343 fc_local_mode = mode;
344
345 /* prepare the init message */
346 fc_check_power(&fc_function_size); /* be sure it's a power of 2 */
347 init.function_size = fc_function_size;
348 init.stack_size = fc_stack_size;
349 init.buffer_size = fc_buffer_size;
350 init.graph_size = fc_graph_size;
351 init.memory_size = fc_memory_size;
352 init.use_pid = fc_use_pid;
353 init.mode = mode;
354 init.verbose = fc_verbose_mode;
355 init.debug = fc_debug_mode;
356 init.time_mode = tmode;
357 if (fc_no_memory_hard)
358 init.memory = -1;
359 else
360 {
361 if (use_memory)
362 init.memory = memory_stack;
363 else
364 init.memory = -1;
365 }
366 fc_gettimeofday(&(init.start_time));
367 sprintf(init.dump_name, "%s", fc_dump_name);
368 sprintf(init.dump_path, "%s", fc_dump_path);
369
370 init.follow = 1; /* some info about dynamic libs will come */
371
372 /* send the init message */
373 fc_debug("sending init message");
374 fc_com_write_init(&init);
375 fc_debug("(pid=%d)", init.first_pid);
376
377 // load start addresses for shared libraries.
378 dl_iterate_phdr(dl_phdr_callback, NULL);
379
380 // mark end of shared library list
381 ldyn.addr = 0;
382 ldyn.name[0] = '\0';
383 fc_com_write_lib(&ldyn);
384
385 /* message to the user */
386 fc_message("Starting %s V%s by Y.Perret", FC_PACKAGE, FC_VERSION);
387 if (!from_rc)
388 fc_message("Profile parameters are:");
389 else
390 fc_message("Profile parameters are (some from rc file):");
391 fc_message(" functions table size : %d", fc_function_size);
392 fc_message(" stack table size : %d", fc_stack_size);
393 fc_message(" graph size : %d", fc_graph_size);
394 fc_message(" buffer size : %d", fc_buffer_size);
395 fc_message(" memory size : %d", fc_memory_size);
396 fc_message(" PID : %d", init.first_pid);
397 fc_message(" used PID : %d", fc_use_pid);
398 fc_message(" verbose : %d", init.verbose);
399 fc_message(" follow dynamic libs : %d", init.follow);
400 if (tmode == FC_MTIME_EXT)
401 fc_message(" time mode : ext");
402 else
403 if (tmode == FC_MTIME_CPU)
404 fc_message(" time mode : cpu");
405 else
406 if (tmode == FC_MTIME_TSC)
407 fc_message(" time mode : tsc");
408 else
409 fc_message(" time mode : error!");
410 if (mode == FC_MODE_SINGLE)
411 fc_message(" profiling mode : no forks / no threads");
412 else
413 if (mode == FC_MODE_FORK)
414 fc_message(" profiling mode : forks allowed / no threads");
415 else
416 if (mode == FC_MODE_THREAD)
417 fc_message(" profiling mode : no forks / threads allowed");
418 else
419 fc_message(" profiling mode : error!");
420 if (fc_allow_debug_hard)
421 fc_message(" debug mode : %s", fc_debug_mode ? "on" : "off");
422 else
423 fc_message(" debug mode : unavailable");
424 if (fc_no_memory_hard)
425 fc_message(" profiling memory : unavailable");
426 else
427 {
428 if (use_memory)
429 fc_message(" profiling memory : on with stack size of %d", memory_stack);
430 else
431 fc_message(" profiling memory : off");
432 }
433 fc_message(" dump-file name : %s", fc_dump_name);
434 fc_message(" dump-file path : %s", fc_dump_path);
435 fc_message("");
436
437 /* if needed, init the memory profiling */
438 if (use_memory)
439 fc_memory_init();
440
441 fc_message("Starting fcmanager...");
442 fc_com_start_manager(fc_shared_memory_id);
443
444 fc_debug("leaving _init");
445 }
446
447 /* called after the end of the profiled program */
448 void __attribute__((destructor)) _fini()
449 {
450 fc_debug("entering _fini");
451
452 /* send the QUIT message, to inform the manager that this process is over */
453 fc_com_quit();
454
455 /* stop the memory profiling */
456 fc_memory_fini();
457
458 /* sleep a little to let childs (if any) starting.
459 else, the manager may detect the end of the pipe
460 even if a child will start soon
461 */
462 if (fc_local_mode != FC_MODE_SINGLE)
463 sleep(2);
464
465 /* stop the com process */
466 fc_com_fini(fc_shared_memory_id);
467
468 fc_debug("leaving _fini");
469 }