>From b0f4d8eeab8ee2dba77247b77ee6ce159b931d7b Mon Sep 17 00:00:00 2001 From: Manuel Francisco Naranjo Date: Mon, 19 Jul 2010 13:15:22 -0300 Subject: [PATCH 1/2] Add Function call tracing modified: Makefile.am modified: acinclude.m4 * Add an option so configure script can be tell to enable function tracing, for good function tracing this options need to be used: --enable-trace \ --enable-debug \ --disable-optimization \ --disable-fortify \ --disable-pie new file: src/cyg-profile.c new file: src/cyg-profile.h * Based on code from http://www.logix.cz/michal/devel/CygProfiler this uses -finstrument-functions from gcc and adds some function to store the tracing to a file, which will be called as bluetoothd-log.$PID modified: src/main.c * Allow users to enable or disable tracing (only available when configured with this option). --- Makefile.am | 4 + acinclude.m4 | 11 ++++ src/cyg-profile.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cyg-profile.h | 40 +++++++++++++ src/main.c | 15 +++++ 5 files changed, 239 insertions(+), 0 deletions(-) create mode 100644 src/cyg-profile.c create mode 100644 src/cyg-profile.h diff --git a/Makefile.am b/Makefile.am index f4bf87d..b146f3f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -216,6 +216,10 @@ CLEANFILES += src/bluetooth.ver src/bluetooth.exp $(builtin_files) man_MANS = src/bluetoothd.8 +if TRACE +src_bluetoothd_SOURCES += src/cyg-profile.h src/cyg-profile.c +endif + if CONFIGFILES conf_DATA += src/main.conf endif diff --git a/acinclude.m4 b/acinclude.m4 index f5fdd66..99d9e4d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -154,6 +154,7 @@ AC_DEFUN([AC_PATH_SNDFILE], [ AC_DEFUN([AC_ARG_BLUEZ], [ debug_enable=no + trace_enable=no optimization_enable=yes fortify_enable=yes pie_enable=yes @@ -288,6 +289,11 @@ AC_DEFUN([AC_ARG_BLUEZ], [ debug_enable=${enableval} ]) + AC_ARG_ENABLE(trace, AC_HELP_STRING([--enable-trace], [enable compiling with function tracing information]), [ + trace_enable=${enableval} + ]) + + AC_ARG_WITH(telephony, AC_HELP_STRING([--with-telephony=DRIVER], [select telephony driver]), [ telephony_driver=${withval} ]) @@ -311,6 +317,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [ CFLAGS="$CFLAGS -g" fi + if (test "${trace_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then + CFLAGS="$CFLAGS -finstrument-functions -DTRACE" + fi + if (test "${optimization_enable}" = "no"); then CFLAGS="$CFLAGS -O0" fi @@ -333,6 +343,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [ AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes") AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes") AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes") + AM_CONDITIONAL(TRACE, test "${trace_enable}" = "yes") AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes") AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes") AM_CONDITIONAL(DUND, test "${dund_enable}" = "yes") diff --git a/src/cyg-profile.c b/src/cyg-profile.c new file mode 100644 index 0000000..20f5597 --- /dev/null +++ b/src/cyg-profile.c @@ -0,0 +1,169 @@ +/* + * cyg-profile.c - CygProfiler runtime functions. + * + * Michal Ludvig + * http://www.logix.cz/michal/devel + * + * cyg-profile.c + * - Compile your program with -finstrument-functions and link + * together with this code. + * - Logging is enabled as soon as your program calls + * cygprofile_enable() and disabled with cygprofile_disable(). + * - Before logging was enabled you can change the name + * of a logfile by calling cygprofile_setfilename(). + */ + +/* Hint: -finstrument-functions, no_instrument_function */ + +#include +#include +#include +#include + +#include "cyg-profile.h" + +#ifdef TRACE + +#define FN_SIZE 100 +#define FN_DEFAULT "bluetoothd-log.%d" + +/* Private variables. */ +static int level=0; +static FILE *logfile=NULL; +static int cyg_profile_enabled=0; +static char cyg_profile_filename[FN_SIZE+1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Static functions. */ +static FILE *openlogfile (const char *filename) + __attribute__ ((no_instrument_function)); +static void closelogfile (void) + __attribute__ ((no_instrument_function)); + +/* Note that these are linked internally by the compiler. + * Don't call them directly! */ +void __cyg_profile_func_enter (void *this_fn, void *call_site) + __attribute__ ((no_instrument_function)); +void __cyg_profile_func_exit (void *this_fn, void *call_site) + __attribute__ ((no_instrument_function)); + +#ifdef __cplusplus +}; +#endif + +void +__cyg_profile_func_enter (void *this_fn, void *call_site) +{ + if(cyg_profile_enabled) + if (logfile || openlogfile(cyg_profile_filename)) + fprintf(logfile, "+ %d %p %p\n", level++, + this_fn, call_site); +} + +void +__cyg_profile_func_exit (void *this_fn, void *call_site) +{ + if(cyg_profile_enabled) + if (logfile || openlogfile(cyg_profile_filename)) + fprintf(logfile, "- %d %p %p\n", level--, + this_fn, call_site); +} + +void +cygprofile_enable (void) +{ + if (!cyg_profile_filename[0]) + cygprofile_setfilename (FN_DEFAULT); + if (!openlogfile (cyg_profile_filename)) + return; + cyg_profile_enabled = 1; +} + +void +cygprofile_disable (void) +{ + cyg_profile_enabled = 0; +} + +int +cygprofile_isenabled (void) +{ return cyg_profile_enabled; } + +int +cygprofile_setfilename (const char *filename) +{ + char *ptr; + + if (cygprofile_isenabled ()) + return -1; + + if (strlen (filename) > FN_SIZE) + return -2; + + ptr = strstr (filename, "%d"); + if (ptr) + { + size_t len; + len = ptr - filename; + snprintf (cyg_profile_filename, len+1, "%s", filename); + snprintf (&cyg_profile_filename[len], FN_SIZE - len, + "%d", getpid ()); + len = strlen (cyg_profile_filename); + snprintf (&cyg_profile_filename[len], FN_SIZE - len, + "%s", ptr + 2); + } + else + snprintf (cyg_profile_filename, FN_SIZE, "%s", filename); + + if (logfile) + closelogfile (); + + return 0; +} + +char * +cygprofile_getfilename (void) +{ + if (!cyg_profile_filename[0]) + cygprofile_setfilename (FN_DEFAULT); + return cyg_profile_filename; +} + +static FILE * +openlogfile (const char *filename) +{ + static int complained = 0; + FILE *file; + + if (complained) + return NULL; + + if (logfile) + return logfile; + + file = fopen(filename, "w"); + if (!file) + { + fprintf (stderr, "WARNING: Can't open logfile '%s': %s\n", + filename, strerror (errno)); + complained = 1; + return NULL; + } + + setlinebuf (file); + logfile = file; + + return file; +} + +static void +closelogfile (void) +{ + if (logfile) + fclose (logfile); +} + +#endif //#ifdef TRACE diff --git a/src/cyg-profile.h b/src/cyg-profile.h new file mode 100644 index 0000000..97be613 --- /dev/null +++ b/src/cyg-profile.h @@ -0,0 +1,40 @@ +/* + * cyg-profile.h - Header file for CygProfiler + * + * Michal Ludvig + * http://www.logix.cz/michal/devel + * + * This source code is a public domain. + * + * See cyg-profile.c for details on usage. + */ + +#ifndef CYG_PROFILE_H +#define CYG_PROFILE_H + +/* Public functions. */ + +#ifdef TRACE + +/* Enable/disable CygProfiler. */ +void cygprofile_enable (void) + __attribute__ ((no_instrument_function)); +void cygprofile_disable (void) + __attribute__ ((no_instrument_function)); + +/* Tell whether CygProfiler is enabled/disabled. */ +int cygprofile_isenabled (void) + __attribute__ ((no_instrument_function)); + +/* Set filename of a logfile. */ +int cygprofile_setfilename (const char *filename) + __attribute__ ((no_instrument_function)); + +/* Query for a filename of a logfile. */ +char *cygprofile_getfilename (void) + __attribute__ ((no_instrument_function)); + + +#endif //#ifdef TRACE + +#endif diff --git a/src/main.c b/src/main.c index 6113217..23a649e 100644 --- a/src/main.c +++ b/src/main.c @@ -60,6 +60,10 @@ #include #endif +#ifdef TRACE +#include "cyg-profile.h" +#endif + #define LAST_ADAPTER_EXIT_TIMEOUT 30 struct main_opts main_opts; @@ -304,6 +308,7 @@ static gchar *option_debug = NULL; static gboolean option_detach = TRUE; static gboolean option_version = FALSE; static gboolean option_udev = FALSE; +static gboolean option_trace = FALSE; static guint last_adapter_timeout = 0; @@ -357,6 +362,10 @@ static GOptionEntry options[] = { "Show version information and exit" }, { "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev, "Run from udev mode of operation" }, +#ifdef TRACE + { "trace", 't', 0, G_OPTION_ARG_NONE, &option_trace, + "Create trace function calls file" }, +#endif { NULL }, }; @@ -393,6 +402,12 @@ int main(int argc, char *argv[]) g_option_context_free(context); +#ifdef TRACE + if (option_trace == TRUE) { + cygprofile_enable(); + } +#endif + if (option_version == TRUE) { printf("%s\n", VERSION); exit(0); -- 1.6.4.4