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