From 93ebb28c47aa021378249dcb34f215be14360230 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 17 May 2008 16:03:18 +0000 Subject: pvtrace --- Makefile | 22 ++++++ Makefile.bsd-wrapper | 7 ++ Makefile.instrument | 8 ++ URL | 4 + instrument.c | 55 ++++++++++++++ stack.c | 62 +++++++++++++++ stack.h | 25 +++++++ symbols.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++ symbols.h | 33 ++++++++ trace.c | 72 ++++++++++++++++++ 10 files changed, 495 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.bsd-wrapper create mode 100644 Makefile.instrument create mode 100644 URL create mode 100644 instrument.c create mode 100644 stack.c create mode 100644 stack.h create mode 100644 symbols.c create mode 100644 symbols.h create mode 100644 trace.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e8a953f --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +# $Id$ +# +# Makefile for the trace utility. +# +# M. Tim Jones +# + +CC = gcc + +OBJS = trace.o symbols.o stack.o + +pvtrace: $(OBJS) + gcc -o $@ $(OBJS) + +.c.o: + $(CC) $(CFLAGS) -Wall -c $< + +install: pvtrace + cp pvtrace /usr/local/bin + +clean: + rm -f pvtrace *.o diff --git a/Makefile.bsd-wrapper b/Makefile.bsd-wrapper new file mode 100644 index 0000000..802c774 --- /dev/null +++ b/Makefile.bsd-wrapper @@ -0,0 +1,7 @@ +# $Id$ + +PROG= pvtrace +SRCS= trace.c symbols.c stack.c +NOMAN= + +.include diff --git a/Makefile.instrument b/Makefile.instrument new file mode 100644 index 0000000..4f0f521 --- /dev/null +++ b/Makefile.instrument @@ -0,0 +1,8 @@ +# $Id$ + +PROG= pvtrace +SRCS= trace.c symbols.c stack.c instrument.c +CFLAGS+= -g -finstrument-functions +NOMAN= + +.include diff --git a/URL b/URL new file mode 100644 index 0000000..4bdd4c0 --- /dev/null +++ b/URL @@ -0,0 +1,4 @@ +# $Id$ +http://www-128.ibm.com/developerworks/linux/library/l-graphvis/?ca=dgr-lnxw06Graphviz +http://www.mtjones.com/developerworks/pvtrace.zip +http://www.gson.org/egypt/egypt.html diff --git a/instrument.c b/instrument.c new file mode 100644 index 0000000..4c9dfa0 --- /dev/null +++ b/instrument.c @@ -0,0 +1,55 @@ +/* $Id$ */ +/******************************************************************** + * File: instrument.c + * + * Instrumentation source -- link this with your application, and + * then execute to build trace data file (trace.txt). + * + * Author: M. Tim Jones + * + */ + +#include +#include + +/* Function prototypes with attributes */ +void main_constructor( void ) + __attribute__ ((no_instrument_function, constructor)); + +void main_destructor( void ) + __attribute__ ((no_instrument_function, destructor)); + +void __cyg_profile_func_enter( void *, void * ) + __attribute__ ((no_instrument_function)); + +void __cyg_profile_func_exit( void *, void * ) + __attribute__ ((no_instrument_function)); + + +static FILE *fp; + + +void main_constructor( void ) +{ + fp = fopen( "trace.txt", "w" ); + if (fp == NULL) exit(-1); +} + + +void main_deconstructor( void ) +{ + fclose( fp ); +} + + +void __cyg_profile_func_enter( void *this, void *callsite ) +{ + fprintf(fp, "E%p\n", (int *)this); +} + + +void __cyg_profile_func_exit( void *this, void *callsite ) +{ + fprintf(fp, "X%p\n", (int *)this); +} + diff --git a/stack.c b/stack.c new file mode 100644 index 0000000..254283a --- /dev/null +++ b/stack.c @@ -0,0 +1,62 @@ +/* $Id$ */ +/******************************************************************** + * File: stack.c + * + * Simple stack implementation. + * + * Author: M. Tim Jones + * + */ + +#include + +#define MAX_ELEMENTS 50 + +static int stack[MAX_ELEMENTS]; +static int index; + +void stackInit( void ) +{ + index = 0; + + return; +} + + +int stackNumElems( void ) +{ + return index; +} + + +unsigned int stackTop( void ) +{ + assert( index > 0 ); + + return (stack[index-1]); +} + + +void stackPush( unsigned int value ) +{ + assert ( index < MAX_ELEMENTS ); + + stack[index] = value; + index++; + + return; +} + + +unsigned int stackPop( void ) +{ + unsigned int value; + + assert( index > 0 ); + + index--; + value = stack[index]; + + return value; +} + diff --git a/stack.h b/stack.h new file mode 100644 index 0000000..ec7418a --- /dev/null +++ b/stack.h @@ -0,0 +1,25 @@ +/* $Id$ */ +/******************************************************************** + * File: stack.h + * + * Simple stack implementation header. + * + * Author: M. Tim Jones + * + */ + +#ifndef __STACK_H +#define __STACK_H + +void stackInit( void ); + +int stackNumElems( void ); + +unsigned int stackTop( void ); + +void stackPush( unsigned int value ); + +unsigned int stackPop( void ); + +#endif /* __STACK_H */ + diff --git a/symbols.c b/symbols.c new file mode 100644 index 0000000..e32e312 --- /dev/null +++ b/symbols.c @@ -0,0 +1,207 @@ +/******************************************************************** + * File: symbols.c + * + * Symbols functions. This file has functions for symbols mgmt + * (such as translating addresses to function names with + * addr2line) and also connectivity matrix functions to keep + * the function call trace counts. + * + * Author: M. Tim Jones + * + */ + +#include +#include +#include +#include +#include "stack.h" +#include "symbols.h" + +func_t functions[MAX_FUNCTIONS]; +unsigned int totals[MAX_FUNCTIONS]; +unsigned int calls[MAX_FUNCTIONS][MAX_FUNCTIONS]; + +char imageName[50]; + +void initSymbol( char *image ) +{ + int from, to; + + strlcpy( imageName, image, sizeof(imageName) ); + + for ( from = 0 ; from < MAX_FUNCTIONS ; from++ ) { + + functions[from].address = 0; + functions[from].funcName[0] = 0; + totals[from] = 0; + + for ( to = 0 ; to < MAX_FUNCTIONS ; to++ ) { + + calls[from][to] = 0; + + } + + } + + return; +} + + +int lookupSymbol( unsigned int address ) +{ + int index; + + for (index = 0 ; index < MAX_FUNCTIONS ; index++) { + + if (functions[index].address == 0) break; + + if (functions[index].address == address) return index; + + } + + assert(0); + + return 0; +} + + +int translateFunctionFromSymbol( unsigned int address, char *func ) +{ + FILE *p; + char line[100]; + int len, i; + + snprintf( line, sizeof(line), "addr2line -e %s -f -s 0x%x", imageName, address ); + + p = popen( line, "r" ); + + if (p == NULL) return 0; + else { + + len = fread( line, 99, 1, p ); + + i = 0; + while ( i < strlen(line) ) { + + if ((line[i] == 0x0d) || (line[i] == 0x0a)) { + func[i] = 0; + break; + } else { + func[i] = line[i]; + } + + i++; + + } + + pclose(p); + + } + + return 1; +} + + +void addSymbol( unsigned int address ) +{ + int index; + + for (index = 0 ; index < MAX_FUNCTIONS ; index++) { + + if (functions[index].address == address) return; + + if (functions[index].address == 0) break; + + } + + if (index < MAX_FUNCTIONS) { + + functions[index].address = address; + + translateFunctionFromSymbol( address, functions[index].funcName ); + + } else { + + assert( 0 ); + + } + + return; +} + + +void addCallTrace( unsigned int address ) +{ + + if (stackNumElems()) { + calls[lookupSymbol(stackTop())][lookupSymbol(address)]++; + } + + return; +} + + +void emitSymbols( void ) +{ + int from, to; + FILE *fp; + + fp = fopen("graph.dot", "w"); + if (fp == NULL) { + printf("Couldn't open graph.dot\n"); + exit(0); + } + + fprintf(fp, "digraph %s {\n\n", imageName ); + + /* Identify node shapes */ + for (from = 0 ; from < MAX_FUNCTIONS ; from++) { + + if (functions[from].address == 0) break; + + for (to = 0 ; to < MAX_FUNCTIONS ; to++) { + + if (functions[to].address == 0) break; + + if (calls[from][to]) totals[from]++; + + } + + if (totals[from]) { + + fprintf( fp, " %s [shape=rectangle]\n", functions[from].funcName ); + + } else { + + fprintf( fp, " %s [shape=ellipse]\n", functions[from].funcName ); + + } + + } + + /* Emit call graph */ + for (from = 0 ; from < MAX_FUNCTIONS ; from++) { + + if (functions[from].address == 0) break; + + for (to = 0 ; to < MAX_FUNCTIONS ; to++) { + + if (calls[from][to]) { + fprintf( fp, " %s -> %s [label=\"%d calls\" fontsize=\"10\"]\n", + functions[from].funcName, functions[to].funcName, + calls[from][to] ); + } + + if (functions[to].address == 0) break; + + } + + } + + fprintf( fp, "\n}\n" ); + + fclose(fp); + + return; +} + diff --git a/symbols.h b/symbols.h new file mode 100644 index 0000000..bf450ba --- /dev/null +++ b/symbols.h @@ -0,0 +1,33 @@ +/* $Id$ */ +/******************************************************************** + * File: symbols.h + * + * Symbols types and prototypes file. + * + * Author: M. Tim Jones + * + */ + +#ifndef __SYMBOLS_H +#define __SYMBOLS_H + +#define MAX_FUNCTIONS 200 +#define MAX_FUNCTION_NAME 50 + +typedef struct { + unsigned int address; + char funcName[MAX_FUNCTION_NAME+1]; +} func_t; + + +void initSymbol( char *imageName ); + +int lookupSymbol( unsigned int address ); + +void addSymbol( unsigned int address ); + +void addCallTrace( unsigned int address ); + +void emitSymbols( void ); + +#endif /* __SYMBOLS_H */ diff --git a/trace.c b/trace.c new file mode 100644 index 0000000..d5975a4 --- /dev/null +++ b/trace.c @@ -0,0 +1,72 @@ +/* $Id$ */ +/******************************************************************** + * File: trace.c + * + * main function for the pvtrace utility. + * + * Author: M. Tim Jones + * + */ + +#include +#include +#include +#include +#include "symbols.h" +#include "stack.h" + + +int main( int argc, char *argv[] ) +{ + FILE *tracef; + char type; + unsigned int address; + + if (argc != 2) { + + printf("Usage: pvtrace \n\n"); + exit(-1); + + } + + initSymbol( argv[1] ); + stackInit(); + + tracef = fopen("trace.txt", "r"); + + if (tracef == NULL) { + printf("Can't open trace.txt\n"); + exit(-1); + } + + while (!feof(tracef)) { + + fscanf( tracef, "%c0x%x\n", &type, &address ); + + if (type == 'E') { + + /* Function Entry */ + + addSymbol( address ); + + addCallTrace( address ); + + stackPush( address ); + + } else if (type == 'X') { + + /* Function Exit */ + + (void) stackPop(); + + } + + } + + emitSymbols(); + + fclose( tracef ); + + return 0; +} + -- cgit v1.2.3