From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/lib/direct/trace.c | 676 +++++++++++++++++++++++++++++++++++++ 1 file changed, 676 insertions(+) create mode 100755 Source/DirectFB/lib/direct/trace.c (limited to 'Source/DirectFB/lib/direct/trace.c') diff --git a/Source/DirectFB/lib/direct/trace.c b/Source/DirectFB/lib/direct/trace.c new file mode 100755 index 0000000..d895333 --- /dev/null +++ b/Source/DirectFB/lib/direct/trace.c @@ -0,0 +1,676 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef PIC +#define DYNAMIC_LINKING +#endif + + +#if DIRECT_BUILD_TRACE + +#ifdef DYNAMIC_LINKING +#include +#endif + +#define MAX_BUFFERS 200 +#define MAX_LEVEL 200 + +#define NAME_LEN 92 + + +typedef enum { + TF_NONE = 0x00000000, + + TF_DEBUG = 0x00000001 +} TraceFlags; + +typedef struct { + void *addr; + TraceFlags flags; +} Trace; + +struct __D_DirectTraceBuffer { + pid_t tid; + char *name; + int level; + bool in_trace; + Trace trace[MAX_LEVEL]; +}; + +/**************************************************************************************************/ + +static DirectTraceBuffer *buffers[MAX_BUFFERS]; +static int buffers_num = 0; +static pthread_mutex_t buffers_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t trace_key = -1; + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +static void +buffer_destroy( void *arg ) +{ + int i; + DirectTraceBuffer *buffer = arg; + + pthread_mutex_lock( &buffers_lock ); + + /* Remove from list. */ + for (i=0; itid = direct_gettid(); + buffer->name = name ? strdup( name ) : NULL; + + buffers[buffers_num++] = buffer; + + pthread_mutex_unlock( &buffers_lock ); + } + + return buffer; +} + +/**************************************************************************************************/ + +typedef struct { + long offset; + char name[NAME_LEN]; +} Symbol; + +typedef struct { + DirectLink link; + + char *filename; + Symbol *symbols; + int capacity; + int num_symbols; +} SymbolTable; + +static DirectLink *tables = NULL; +static pthread_mutex_t tables_lock = PTHREAD_MUTEX_INITIALIZER; + + +__attribute__((no_instrument_function)) +static void +add_symbol( SymbolTable *table, long offset, const char *name ) +{ + Symbol *symbol; + + if (table->num_symbols == table->capacity) { + Symbol *symbols; + int capacity = table->capacity * 2; + + if (!capacity) + capacity = 256; + + symbols = malloc( capacity * sizeof(Symbol) ); + if (!symbols) { + D_WARN( "out of memory" ); + return; + } + + direct_memcpy( symbols, table->symbols, table->num_symbols * sizeof(Symbol) ); + + free( table->symbols ); + + table->symbols = symbols; + table->capacity = capacity; + } + + symbol = &table->symbols[ table->num_symbols++ ]; + + symbol->offset = offset; + + direct_snputs( symbol->name, name, NAME_LEN ); +} + +__attribute__((no_instrument_function)) +static SymbolTable * +load_symbols( const char *filename ) +{ + SymbolTable *table; + FILE *fp = NULL; + bool is_pipe = false; + char file[1024]; + char line[1024]; + int command_len; + char *command; + const char *full_path = filename; + char *tmp; + + if (filename) { + if (access( filename, R_OK ) < 0 && errno == ENOENT) { + int len; + + if ((len = readlink( "/proc/self/exe", file, sizeof(file) - 1 )) < 0) { + D_PERROR( "Direct/Trace: readlink( \"/proc/self/exe\" ) failed!\n" ); + return NULL; + } + + file[len] = 0; + + + tmp = strrchr( file, '/' ); + if (!tmp) + return NULL; + + if (strcmp( filename, tmp + 1 )) + return NULL; + + full_path = file; + } + } + else { + int len; + + if ((len = readlink( "/proc/self/exe", file, sizeof(file) - 1 )) < 0) { + D_PERROR( "Direct/Trace: readlink( \"/proc/self/exe\" ) failed!\n" ); + return NULL; + } + + file[len] = 0; + + full_path = file; + } + + command_len = strlen( full_path ) + 32; + command = alloca( command_len ); + + /* First check if there's an "nm-n" file. */ + tmp = strrchr( full_path, '/' ); + if (!tmp) + return NULL; + + *tmp = 0; + snprintf( command, command_len, "%s/nm-n.%s", full_path, tmp + 1 ); + *tmp = '/'; + + if (access( command, R_OK ) == 0) { + fp = fopen( command, "r" ); + if (!fp) + D_PERROR( "Direct/Trace: fopen( \"%s\", \"r\" ) failed!\n", command ); + } + else { + snprintf( command, command_len, "%s.nm", full_path ); + if (access( command, R_OK ) == 0) { + fp = fopen( command, "r" ); + if (!fp) + D_PERROR( "Direct/Trace: fopen( \"%s\", \"r\" ) failed!\n", command ); + } + } + + /* Fallback to live mode. */ + if (!fp) { + snprintf( command, command_len, "nm -n %s", full_path ); + + fp = popen( command, "r" ); + if (!fp) { + D_PERROR( "Direct/Trace: popen( \"%s\", \"r\" ) failed!\n", command ); + return NULL; + } + + is_pipe = true; + } + + table = calloc( 1, sizeof(SymbolTable) ); + if (!table) { + D_OOM(); + goto out; + } + + if (filename) + table->filename = strdup( filename ); + + while (fgets( line, sizeof(line), fp )) { + int n; + int digits = sizeof(long) * 2; + long offset = 0; + int length = strlen(line); + + if (line[0] == ' ' || length < (digits + 5) || line[length-1] != '\n') + continue; + + if (line[digits + 1] != 't' && line[digits + 1] != 'T' && line[digits + 1] != 'W') + continue; + + if (line[digits] != ' ' || line[digits + 2] != ' ' || line[digits + 3] == '.') + continue; + + for (n=0; n= '0' && c <= '9') + offset |= c - '0'; + else + offset |= c - 'a' + 10; + } + + line[length-1] = 0; + + add_symbol( table, offset, line + digits + 3 ); + } + +out: + if (is_pipe) + pclose( fp ); + else + fclose( fp ); + + return table; +} + +__attribute__((no_instrument_function)) +static int +compare_symbols(const void *x, const void *y) +{ + return *((const long*) x) - *((const long*) y); +} + +__attribute__((no_instrument_function)) +static SymbolTable * +find_table( const char *filename ) +{ + SymbolTable *table; + + if (filename) { + direct_list_foreach (table, tables) { + if (table->filename && !strcmp( filename, table->filename )) + return table; + } + } + else { + direct_list_foreach (table, tables) { + if (!table->filename) + return table; + } + } + + return NULL; +} + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +const char * +direct_trace_lookup_symbol( const char *filename, long offset ) +{ + Symbol *symbol; + SymbolTable *table; + + pthread_mutex_lock( &tables_lock ); + + table = find_table( filename ); + if (!table) { + table = load_symbols( filename ); + if (!table) { + pthread_mutex_unlock( &tables_lock ); + return false; + } + + direct_list_prepend( &tables, &table->link ); + } + + pthread_mutex_unlock( &tables_lock ); + + symbol = bsearch( &offset, table->symbols, table->num_symbols, + sizeof(Symbol), compare_symbols ); + + return symbol ? symbol->name : NULL; +} + +__attribute__((no_instrument_function)) +const char * +direct_trace_lookup_file( void *address, void **ret_base ) +{ +#ifdef DYNAMIC_LINKING + Dl_info info; + + if (dladdr( address, &info )) { + if (ret_base) + *ret_base = info.dli_fbase; + + return info.dli_fname; + } + else +#endif + { + if (ret_base) + *ret_base = NULL; + } + + return NULL; +} + +__attribute__((no_instrument_function)) +void +direct_trace_print_stack( DirectTraceBuffer *buffer ) +{ +#ifdef DYNAMIC_LINKING + Dl_info info; +#endif + int i; + int level; + + if (!direct_config->trace) + return; + + if (!buffer) + buffer = get_trace_buffer(); + + if (buffer->in_trace) + return; + + buffer->in_trace = true; + + + level = buffer->level; + if (level > MAX_LEVEL) { + D_WARN( "only showing %d of %d items", MAX_LEVEL, level ); + level = MAX_LEVEL; + } + else if (level == 0) { + buffer->in_trace = false; + return; + } + + direct_log_lock( NULL ); + + if (buffer->name) + direct_log_printf( NULL, "(-) [%5d: -STACK- '%s']\n", buffer->tid, buffer->name ); + else + direct_log_printf( NULL, "(-) [%5d: -STACK- ]\n", buffer->tid ); + + for (i=level-1; i>=0; i--) { + void *fn = buffer->trace[i].addr; + +#ifdef DYNAMIC_LINKING + if (dladdr( fn, &info )) { + if (info.dli_fname) { + const char *symbol = NULL;//info.dli_sname; + + if (!symbol) { + symbol = direct_trace_lookup_symbol(info.dli_fname, (long)(fn - info.dli_fbase)); + if (!symbol) { + symbol = direct_trace_lookup_symbol(info.dli_fname, (long)(fn)); + if (!symbol) { + if (info.dli_sname) + symbol = info.dli_sname; + else + symbol = "??"; + } + } + } + + direct_log_printf( NULL, " #%-2d 0x%08lx in %s () from %s [%p]\n", + level - i - 1, (unsigned long) fn, symbol, info.dli_fname, info.dli_fbase ); + } + else if (info.dli_sname) { + direct_log_printf( NULL, " #%-2d 0x%08lx in %s ()\n", + level - i - 1, (unsigned long) fn, info.dli_sname ); + } + else + direct_log_printf( NULL, " #%-2d 0x%08lx in ?? ()\n", + level - i - 1, (unsigned long) fn ); + } + else +#endif + { + const char *symbol = direct_trace_lookup_symbol(NULL, (long)(fn)); + direct_log_printf( NULL, " #%-2d 0x%08lx in %s ()\n", + level - i - 1, (unsigned long) fn, symbol ? symbol : "??" ); + } + } + + direct_log_printf( NULL, "\n" ); + direct_log_unlock( NULL ); + + buffer->in_trace = false; +} + +__attribute__((no_instrument_function)) +void +direct_trace_print_stacks( void ) +{ + int i; + DirectTraceBuffer *buffer = get_trace_buffer(); + + if (buffer->level) + direct_trace_print_stack( buffer ); + + pthread_mutex_lock( &buffers_lock ); + + for (i=0; ilevel) + direct_trace_print_stack( buffers[i] ); + } + + pthread_mutex_unlock( &buffers_lock ); +} + +__attribute__((no_instrument_function)) +int +direct_trace_debug_indent( void ) +{ + int in; + DirectTraceBuffer *buffer = get_trace_buffer(); + int level = buffer->level - 1; + + if (level < 0) + return 0; + + buffer->trace[level--].flags |= TF_DEBUG; + + for (in=0; level>=0; level--) { + if (buffer->trace[level].flags & TF_DEBUG) + in++; + } + + return in; +} + +__attribute__((no_instrument_function)) +DirectTraceBuffer * +direct_trace_copy_buffer( DirectTraceBuffer *buffer ) +{ + int level; + DirectTraceBuffer *copy; + + if (!buffer) + buffer = get_trace_buffer(); + + level = buffer->level; + if (level > MAX_LEVEL) { + D_WARN( "only copying %d of %d items", MAX_LEVEL, level ); + level = MAX_LEVEL; + } + + copy = calloc( 1, sizeof(*buffer) - sizeof(buffer->trace) + sizeof(buffer->trace[0]) * level ); + if (!copy) + return NULL; + + if (buffer->name) + copy->name = strdup( buffer->name ); + + copy->tid = buffer->tid; + copy->level = buffer->level; + + direct_memcpy( copy->trace, buffer->trace, level * sizeof(buffer->trace[0]) ); + + return copy; +} + +__attribute__((no_instrument_function)) +void +direct_trace_free_buffer( DirectTraceBuffer *buffer ) +{ + if (buffer->name) + free( buffer->name ); + + free( buffer ); +} + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +void +__cyg_profile_func_enter (void *this_fn, + void *call_site) +{ + if (direct_config->trace) { + DirectTraceBuffer *buffer = get_trace_buffer(); + int level = buffer->level++; + Trace *trace = &buffer->trace[level]; + + if (level < MAX_LEVEL) { + trace->addr = this_fn; + trace->flags = TF_NONE; + } + } +} + +__attribute__((no_instrument_function)) +void +__cyg_profile_func_exit (void *this_fn, + void *call_site) +{ + if (direct_config->trace) { + DirectTraceBuffer *buffer = get_trace_buffer(); + + if (buffer->level > 0) + buffer->level--; + } +} + +#else + +const char * +direct_trace_lookup_symbol( const char *filename, long offset ) +{ + return NULL; +} + +const char * +direct_trace_lookup_file( void *address, void **ret_base ) +{ + if (ret_base) + *ret_base = NULL; + + return NULL; +} + +void +direct_trace_print_stack( DirectTraceBuffer *buffer ) +{ +} + +void +direct_trace_print_stacks( void ) +{ +} + +int +direct_trace_debug_indent( void ) +{ + return 0; +} + +DirectTraceBuffer * +direct_trace_copy_buffer( DirectTraceBuffer *buffer ) +{ + return NULL; +} + +void +direct_trace_free_buffer( DirectTraceBuffer *buffer ) +{ +} + +#endif + -- cgit