-
Notifications
You must be signed in to change notification settings - Fork 24
Update of original etrace program.
elcritch/etrace
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
etrace: A run-time tracing tool ------------------------------- These source files comprise a simple but efficient utility that allows the display of a function call tree in a C program at run-time. It is also possible to dump the results of a program execution to an ASCII file for later examination. * ptrace.c compiles your code to enable this run-time tracing * etrace is a Python script that will perform the run-time tracing by displaying the function names as they are called * etrace.pl is a Perl script that will perform the run-time tracing by displaying the function names as they are called. Moreover, etrace.pl can be used to trace dynamic libraries. License ------- This is free software placed in the public domain. Enjoy! Pre-requisites -------------- - gcc version 2.95 or later. - The presence of the 'nm' utility on your machine, with a compatible BSD output. - Python 1.5 or later (for etrace) or Perl (for etrace.pl). Portability ----------- This code is known to run under Linux, FreeBSD, Solaris, and HPUX. Example using etrace -------------------- There is an example in the example/ sub-dir. To compile it, do: % cd example % make You should now have an executable called "crumble". Running it should give you a recipe for an apple crumble, with 1-second pauses between sentences to demonstrate the run-time ability. Now let's get to this function call tree: To get the tree at run-time, open two terminals. In the first terminal: % cd etrace/example % ../src/etrace crumble In the second terminal: % cd etrace/example % crumble Both terminals need to be in the same directory. Data are exchanged between the running process you are trying to monitor and the 'etrace' script through a named pipe in this directory. You should see this: main | Crumble_make_apple_crumble | | Crumble_buy_stuff | | | Crumble_buy | | | Crumble_buy (total: 5 times) | | Crumble_prepare_apples | | | Crumble_skin_and_dice | | Crumble_mix | | Crumble_finalize | | | Crumble_put | | | Crumble_put (total: 2 times) | | Crumble_cook | | | Crumble_put | | | Crumble_bake To get the tree into a file for later use, do the following: % cd etrace/example % touch TRACE % crumble % ../src/etrace crumble > log The trace has been saved to a file called 'log' in the current directory. Example using etrace.pl ----------------------- There is an example in the example/ sub-dir. To compile it, do: % cd example % make You should now have an executable called "crumble". Running it should give you a recipe for an apple crumble, with 1-second pauses between sentences to demonstrate the run-time ability. Now let's get to this function call tree: To get the tree at run-time, open two terminals. In the first terminal: % cd etrace/example % ../src/etrace.pl crumble In the second terminal: % cd etrace/example % crumble Both terminals need to be in the same directory. Data are exchanged between the running process you are trying to monitor and the 'etrace' script through a named pipe in this directory. You should see this: \-- main | \-- Crumble_make_apple_crumble | | \-- Crumble_buy_stuff | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | \-- Crumble_prepare_apples | | | \-- Crumble_skin_and_dice | | \-- Crumble_mix | | \-- Crumble_finalize | | | \-- Crumble_put | | | \-- Crumble_put | | \-- Crumble_cook | | | \-- Crumble_put | | | \-- Crumble_bake To get the tree into a file for later use, you can do the following: % cd etrace/example % touch TRACE % crumble % ../src/etrace.pl crumble > log or % cd etrace/example % touch TRACE % crumble % ../src/etrace.pl crumble TRACE > log Either way, the trace has been saved to a file called 'log' in the current directory. To see how to modify ptrace.c to work with a dynamic library, look at the example2 directory. The sources there also create a stand-alone executable, but the PTRACE_REFERENCE_FUNCTION macro is defined just as it would be for a dynamic library. How does it work? ----------------- gcc 2.95 has a nifty feature called "instrument-functions", that adds a couple of function calls to all functions in your code. Every time a function starts, a function called __cyg_profile_func_enter() is called, and every time a function exits, a function called __cyg_profile_func_exit() is called. The code in ptrace.c simply redirects the information gathered at each call to a text file. Now, if you examine closely what you get from this output, you will see that only the binary addresses of functions are printed out. To make the link to true function names, you need to interpret the binary and make the list of associations. There are many ways of doing this, and to be truly platform-independent you should have a look at the BFD library from the GNU project. etrace implements a much simpler (but of course much less portable) solution by using the 'nm' utility to dump a list of all defined symbols and associated addresses. The link between them and the pretty printing as a function call tree is all done in the 'etrace' script. etrace.pl works in a manner similarly to etrace. Up to output pretty-printing, it works the same as etrace on stand-alone programs. If the first line of the TRACE file is marked "REFERENCE", however, it uses the values provided to calculate where the reference function actually resides in memory, and compares the difference between that address and the address in the symbol table; this offset is then applied to all the function addresses in the trace. This feature is enabled by defining the PTRACE_REFERENCE_FUNCTION in ptrace.c and is essential to correctly map the function names when tracing a dynamic library (this feature is optional for stand-alone programs). ptrace/etrace usage ------------------- The ptrace.c module will look for a file called "TRACE" in the current directory. If no such file can be found, nothing will be logged. You still get the penalty associated to the two function calls but nothing else changes. If a TRACE file can be found, log data will be appended to it. The idea is to make the TRACE file a fifo so that another process can read from it and display the informations at run-time. This is exactly what the 'etrace' script does. You do not have to create the fifo yourself, one will be created upon startup of 'etrace', and will be deleted afterwards. 'etrace' needs to know the name of the executable you are trying to trace, to retrieve the symbols (with 'nm'). This is the only argument to the script. 'etrace.pl' takes two arguments. The first argument, which is mandatory, is either the name of the executable you want to trace, or the name of the symbol file (produced by nm) of the executable you want to trace. The second argument, which is optional, is either the name of the trace file produced by ptrace (if you want to see the function calls after the program has finished running) or the name to use for the FIFO (in which case you will need to make sure ptrace.c writes to a file with that same name). How to use it in your code -------------------------- To trace a stand-alone program, there is no need to #include any additional file. Just link your code against ptrace.c and use the -finstrument-functions option as a compile option for gcc. This should do it. Now when you want to trace at run-time (handy to see where the code breaks in case of segfault), open two terminals. Launch first 'etrace myprogram' in one terminal, and 'myprogram' in the other. Remember both need to be in the same directory for the magic to work. If you want to log the trace to a file, create an empty file called TRACE in the current directory, launch your program, and examine the results using 'etrace myprogram'. If you want to trace a library, you need to provide ptrace.c with the name of a reference function. The name and address of this function, once loaded, will be the first line output to the trace file, and will be used by etrace.pl to correctly map the function pointers to the symbol names. To provide ptrace.c with the reference function, simply set the macro PTRACE_REFERENCE_FUNCTION to the name of a function in your library. You may #include any header files needed to make this function visible in the "User Macros" section of ptrace.c. How to modify it ---------------- If you do not like the name of the trace file (TRACE) you can actually rename that both in ptrace.c and etrace. You could also use a dynamic file name but you need then a way of exchanging the file name between both processes. If you prefer, you could have ptrace.c redirect its output to a socket and etrace retrieve it as a client. This would substantially increase the amount of code but could be interesting for remotely debugging an application. The output of your 'nm' command might slightly change from the BSD standard (identical to Linux, Solaris, and to some extent to the HPUX output). You will need to modify the simplistic parser implemented in 'etrace' to handle these changes. You could also use the tracing feature to have 'ptrace.c' send many more informations through the line, like memory allocations, file operations, etc. This might make the output somewhat harder to read and is most probably better handled by a debugger. Well anyway, this is just one possible use of the function instrumentation feature of gcc 2.95. Thanks to the gcc team for this VERY useful tool! Feedback -------- Feedback is always welcome. However, this code is not supported. This is only 80 lines of Python and 100 lines of C, so if you need additional features I'd say you are better off on your own. :-) N. Devillard Wed May 9 15:29:04 CEST 2001 V. Chudnovsky Mon Mar 8 2004
About
Update of original etrace program.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published