views:

286

answers:

11

I am debugging a C program (GCC and GDB in Linux and Visual Studio in Windows) that gives different results on two different architectures. I'd like to compare execution on each architecture by tracing the changes to the values stored in variables in order to locate differences.

file main.c, line 234. Variable A changes from 34 to 23
file main.c, line 236. Variable B changes from 0 to 2
.....
etc.

Can the compiler be instructed to instrument to this effect, without manually littering the source with printf statements?

A: 

You can tell gdb to break whenever some instruction modifies your variable. IIRC the command is 'watch'. E.g. 'watch A', or 'watch *(int*)0x123456'.

And you can even tell it to break when someone reads it, with 'rwatch'.

I know, but this is only when you know the variable "to follow". I just want to dump on screen all the changes, so I compare results on both architectures, and know exactly when both programs start to diverge
Werner
A: 

You can tell gcc to instrument function calls: -finstrument-functions. This doesn't get you on the granularity of assignment, but close if you pack some elementary functionalities into inline functions.

Jens Gustedt
A: 

I think the program ctrace might be what you're after; it was available in AT&T Unix (back in the days when AT&T owned Unix), but the URL is to the Sun manual page. You can probably find it, therefore, on the other proprietary versions of Unix (AIX, HP-UX, SCO); it is not clear that there is a version for Linux.

The CTrace library at SourceForge is not the same thing at all.

Jonathan Leffler
+4  A: 

There are several factors to consider in an implicit solution:

  • C is barely type aware. For example if you used @Jens Gustedt's suggestion of instrumenting functions, you still have the problem of determining what exactly you're looking at on the stack, and how to appropriately print out the values. IIRC, instrumenting functions won't give you the prototype of the upcoming function, nor will it provide a handy struct with pointers to those values. This would be more akin to C++ templating. You'd have to write an enter/exit function that was aware of the prototypes of all the functions, and have inside knowledge of the precise calling convention and packing arrangements for your variables.
  • You need to compile with debugging symbols, in order to identify what memory was associated with a variable defined in your code, and when those variables are being modified.
  • More complex types do not have a standard way to be printed (structs for example), even in C++. You'd need to have printing functions that conform to some kind of interface.
  • Pointers and arrays of indeterminate length will be very difficult to handle. You'd need to test for NULL pointers, and know array sizes in advance to correctly print their values.

I've attempted something similar to your "printf at function entry" in an existing project I'm working on. It's kind of useful for important functions, but I've gotten far more go out of asserting values are in the expected ranges at function entry and exit. Here's the logging header and source, which demonstrate how to greatly simplify the printing of lines, functions and other useful information around your manual tracing. You'll notice many of my types have a corresponding *_valid() function, and assertions surrounding their use. As soon as my program runs off the tracks (which I assure you is quite frequent during debugging), the asserts will fire and I can analyse the situation via the stack trace.

You may also find this answer useful regarding both the difficulty of doing this stuff with C alone, and how to work around it using macros.

Your best bet if you need this done implicitly is via GDB, presumably you can write scripts to analyse changes after each instruction, and intelligently determine and print types using the debugging info provided by -g.

Matt Joiner
+1  A: 

Valgrind can trace all stores automatically, although the standard tools don't easily provide an explicit trace. You would have to write your own valgrind tool, e.g. by modifying cachegrind, to trace all Ist_Store instructions.

Alas, valgrind doesn't work on Windows.

Martin v. Löwis
Alas indeed, there are many great tools that don't work on Windows :@
Matt Joiner