aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile22
-rw-r--r--Makefile.bsd-wrapper7
-rw-r--r--Makefile.instrument8
-rw-r--r--URL4
-rw-r--r--instrument.c55
-rw-r--r--stack.c62
-rw-r--r--stack.h25
-rw-r--r--symbols.c207
-rw-r--r--symbols.h33
-rw-r--r--trace.c72
10 files changed, 495 insertions, 0 deletions
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 <mtj@mtjones.com>
+#
+
+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 <bsd.prog.mk>
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 <bsd.prog.mk>
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 <mtj@mtjones.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* 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 <mtj@mtjones.com>
+ *
+ */
+
+#include <assert.h>
+
+#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 <mtj@mtjones.com>
+ *
+ */
+
+#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 <mtj@mtjones.com>
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#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 <mtj@mtjones.com>
+ *
+ */
+
+#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 <mtj@mtjones.com>
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#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 <image>\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;
+}
+