
NOTE: Also see subdirectory "example" for an example application.

--

MPRPC

MPRPC is an environment variable that must be set prior to calling
function mpr().  It is set using the program mprpc.  MPRPC is used
internally to traverse and display the call chain during each
alloc/free.  If MPRPC is unset, the call to function mpr() will fail
with return code -1.

Note that in order for mpr to be able to traverse the call chain, you
must compile your application with frame-pointer support.  This is
usually true, unless you compile your application with a special flag
(e.g. using -fomit-frame-pointer with GCC), or your compiler optimizes
away assignments to the frame-pointer register (e.g. using -O3 with
sco5's default C compiler).

Here is how to set MPRPC:

	% MPRPC=`mprpc a.out` MPRFI='cat >log' a.out ...

If you're working with a single application, it may be more convenient
to export MPRPC once, instead of having to set it each time you
run your application:

	% export MPRPC=`mprpc a.out`
	% MPRFI='cat >log' a.out ...

However, remember to reset MPRPC if you re-compile your application.

--

MPRFI

MPRFI is a shell pipeline used to filter the alloc/free log
messages.  The pipeline is invoked by function mpr() using popen(3).

MPRFI is most often used to save the messages, untouched, to a
log file:

	% MPRFI='cat >log' a.out ...

If your application does a lot of allocs/frees, it may be worthwhile
to filter the log messages through a compression utility - this can
significantly reduce the size of the log file:

	% MPRFI='gzip -1 >log.gz' a.out ...

If you only wish to catch memory leaks (i.e. you are not interested
in the entire malloc/free history of your program), you can use 'mprlk'
in MPRFI:

	% MPRFI='mprlk >leaks' a.out ...

	After your program exits, file 'leaks' will only contain the
	call chains identified as memory leaks.  You still need to
	pass 'leaks' through the filter 'mpr' to map the call chain
	program counters into function names:

	% mpr leaks
	% mpr leaks | mprcc -c99
	% mpr -f -l leaks | mprcc -c99

If MPRFI is unset, or is set to the empty string, mpr will not log
anything.  This is a convenient way to disable logging without having
to re-compile your program:

	% MPRFI= a.out ...
	or
	% unset MPRFI
	% a.out ...

--

mpr [[-f|-F foo.c,bar.c,...] [-l]] [-Ix] [-i foo,bar,...] [-p] a.out [log]

mpr maps program counters of an executable (that were logged as
part of the call chain) into corresponding function names and,
optionally, file names and line numbers.

Its stdin should be the the contents of the log file
(pre-filtered through mprlk if you wish to examine memory leaks):

	To see memory allocation requests:

	% mpr a.out <log	# use stdin
	or
	% mpr a.out log		# use 'log'
	or
	% mpr a.out log.gz	# decompress and use 'log.gz'

	To see memory leaks:

	% mprlk log | mpr a.out

Option -i ignores functions that you do not wish to have displayed
as part of the call chain.  This is useful if you have "wrapper"
functions around calls to malloc/realloc/free that are cluttering
your display.  The argument to option -i should be a list of
comma-separated function names that you wish to ignore:

	void *
	xmalloc(size_t sz)
	{
		void *p = malloc(sz);
		if (!p && sz)
        		abort();
		return p;
	}

	void *
	xrealloc(void *ptr, size_t sz)
	{
		void *p = realloc(ptr, sz);
		if (!p && sz)
        		abort();
		return p;
	}

	Here, the functions xmalloc() and xrealloc() are wrappers around
	calls to malloc() and realloc() that check for allocation
	failures. However, you may not wish to see them in the call
	chain since they were not "really" responsible for the
	allocations - you'd much rather see only their callers;
	invoking mpr with the option "-i xmalloc,xrealloc" will do
	this.

As mentioned above, "," (comma) is the default separator for the list
of function names to be ignored with option -i.  However, if you are
using mpr with a C++ executable, you may need to use a different
separator since "," may appear in a C++ function's argument list.  In
such cases, option -I can be used to specify a different separator:

	% mpr -I"#" -i 'foo(int &, void *)#bar(int)' a.out log

Option -f displays file names in addition to function names.  This
only works for those parts of your application that were compiled
with the "-g" option of the C compiler.  Parts of the program that
were not compiled with "-g" will show empty file names. (As mentioned
in the README file, you must have the GNU debugger GDB installed in
order to use the "-f -l" options of mpr).

Option -l displays line numbers in addition to file names and
function names.  It should be used with option -f.  Again, parts of
the application that were not compiled with "-g" will not show line
number information:

	% mpr -f -l -i xmalloc,xrealloc a.out log

If you use the "-f" option of mpr, then the function names
displayed by mpr will be as you expect.  However, without option
"-f", there is a problem with duplicate function names - functions
with identical names defined in different object files of your
application.  In this case, mpr will append additional "+" characters
to duplicate named functions to distinguish between them (since "+"
cannot be part of a legal C function name).  The particular function
should be obvious from the rest of the call chain displayed by mpr:

	bar.c:

	static void baz()
	{
		p = malloc(...);
	}

	bar()
	{
		baz();
	}

	foo.c:

	static void baz()
	{
		p = malloc(...);
	}

	foo()
	{
		baz();
	}

	Here, both files bar.c and foo.c define a function named
	baz().  If baz() happens to appear in the call chain of any
	alloc/free request, mpr will append a "+" to either foo.c's
	baz() or bar.c's baz() to distinguish between them.  Exactly
	which one should be obvious from the caller of baz() which
	will be the next function in the call chain: it will be
	either foo() or bar().

	If, however, you invoke mpr with option "-f" (and foo.c
	and bar.c were compiled with "-g"), then there is no need
	to add "+" to distinguish between the two baz()'s since
	the file names (foo.c and bar.c) will do this.

Option -F is similar to option -f, but it restricts the set of source
files for which file names are displayed (compared to option -f which
tries to list file names for all source files of the executable):

	% mpr -F foo.c,bar.c -l a.out log

	This will display file names and line numbers only for files
	foo.c and bar.c.

	% mpr -F "`cd src/dir1; echo *.c`" -l a.out log

	This will display file names and line numbers only for the
	source files in directory src/dir1.

Option -p may be useful if you are using mph with a C++ program.
By default, mph will print the parameter list of each C++ function -
this can result in unwieldy looking output.  Option -p omits the
parameter list.

--

mprcc [-c N] [-w N] [log]

mprcc groups memory allocation requests by call chains.
Its stdin should be connected to the stdout of mpr.

mprcc displays the call chain in column 1, the number of allocations
in column 2 and the total amount allocated by the call chain (in
bytes) in column 3:

	% mpr a.out log | mprcc

If you wish to see memory leaks grouped by call chains, use
the mprlk filter prior to invoking mpr.  This will then show the
call chains responsible for leaks in column 1, the number of
allocations that were leaked in column 2 and the total amount that
was leaked by each call chain in column 3:

	% mprlk log | mpr a.out | mprcc

Option -c sets the length of the call chains.  By default it is set
to 1, so you get allocation requests grouped only by the last
function to call the memory allocation routines.  Setting it to a
higher value may make it easier for you to track down functions
responsible for allocations by showing longer call chains leading
up to the allocation requests:

	To see memory allocation requests grouped by call chains
	of length 9:

	% mpr -f -l a.out log | mprcc -c9

Note that the "granularity" of the call chains that mprcc uses to
group allocation requests is determined by how you invoke mpr.
If you invoke mpr without options "-f -l", then the granularity
is per function; if you invoke mpr with options "-f -l" then the
granularity is per function and per line:

	foo()
	{
		p1 = malloc(...);
		p2 = malloc(...);
		...
	}

	The calls to malloc() in function foo() will be lumped
	together in one call chain if invoked as

	% mpr a.out log | mprcc

	The calls to malloc() in function foo() will appear in
	different call chains if invoked as

	% mpr -f -l a.out log | mprcc

Option -w sets the width of the display.  By default, it is set
to 80.  If you wish to see more of the call chain, but doing so
results in funny looking output (since mprcc tries to line up the
last 2 columns), then use option -w to increase the width:

	To see the entire call chain on a 132 column wide output:

	% mpr -f -l a.out log | mprcc -c99 -w132

--

mprlk [log]

mprlk identifies those allocation requests that lead to memory leaks.
Its stdin should be the contents of the log file.

It is used most often as a pre-filter for mpr or mprsz:

	To examine memory leaks:

	% mprlk <log | mpr a.out	# use stdin
	or
	% mprlk log | mpr a.out		# use 'log'
	or
	% mprlk log.gz | mpr a.out	# decompress and use 'log.gz'

	To examine memory leaks grouped by function call chains of
	length 3:

	% mprlk log | mpr a.out | mprcc -c3

	To examine memory leaks grouped by size:

	% mprlk log | mprsz

If you only wish to catch memory leaks (i.e. you are not interested
in the entire malloc/free history of your program), you can use 'mprlk'
in MPRFI:

	% MPRFI='mprlk >leaks' a.out ...

	After your program exits, file 'leaks' will only contain the
	call chains identified as memory leaks.  You still need to
	pass 'leaks' through the filter 'mpr' to map the call chain
	program counters into function names:

	% mpr leaks
	% mpr leaks | mprcc -c99
	% mpr -f -l leaks | mprcc -c99

--

mprhi [-c N] [-w N] [-b N] [log]

mprhi displays a histogram of the total amount of memory allocated
by your application.  Its stdin should be the contents of the log
file.

mprhi uses '*' to represent a block of allocated memory with a
default block size of 1024 bytes.  Option -b can be used to change
the default block size:

	To see a histogram with a block size of 2048:

	% mprhi -b2048 <log	# use stdin
	or
	% mprhi -b2048 log	# use 'log'
	or
	% mprhi -b2048 log.gz	# decompress and use 'log.gz'

If you wish to see call chains alongside the histogram, then use
option -c to set the length of the call chains to display.  In
this case you should pre-filter the log file through program mpr:

	To see a histogram with a block size of 2048 and function
	name, file name and line number call chains of length 5:

	% mpr -f -l a.out log | mprhi -b2048 -c5

Note that without option -c, mprhi will not show adjacent histogram
entries with the same length, i.e. the output is "compressed" to show
only changes in the amount of allocated memory in "granularities" of
the block size.  This, coupled with option -b for showing a bigger
block size, can give you a quick idea of your application's memory
alloc/free history, without having to wade through an enormous amount of
output, especially if your application does thousands of allocs/frees.

However, with option -c, mprhi is much more verbose and shows one line
for *every* alloc/free.  This can help you pin down the call chains
(or sequence of call chains) responsible for the biggest allocs and
frees, and also precisely when they did so.

Option -w sets the width of the display.  By default, it is set to
80.  It is only useful when you use option -c to show call chains
alongside the histogram.  In this case, mprhi tries to right justify
the call chains to line up in column 80 (the histogram is easier to
visualize by separating it from the call chain).  However, if the
output scrolls off the end or if the call chains are too close to
the histogram, then you can either (1) use option -b to increase the
block size or (2) decrease the length of the call chains or (3) use
option -w to increase the width of the display.

--

mprsz [log]

mprsz groups memory allocation requests by size.

Its stdin should be the the contents of the log file
(pre-filtered through mprlk if you wish to examine memory leaks).

The output consists of 2 columns: column 1 is the size and column 2
is the number of allocations of that size:

	To examine memory allocation requests grouped by size:

	% mprsz <log	# use stdin
	or
	% mprsz log	# use 'log'
	or
	% mprsz log.gz	# decompress and use 'log.gz'

	To examine memory allocation leaks grouped by size:

	% mprlk log | mprsz

--

extern int mcheck(void (*abortfunc)())

Function mcheck() is not part of mpr - it's actually part of the
GNU malloc library that mpr uses.  However, it can be used to catch a
class of memory violation errors that mpr does not address so it is
described here.  For convenience, a copy of mcheck() is included in
library libmpr.a.

Calling mcheck() enables checks for the following common memory
violations:
	- memory clobbered before allocated block
	- memory clobbered past end of allocated block
	- block freed twice

By default, mcheck() is called automatically the first time your
application calls malloc().

--

Syntax of the log file

You do not need to understand the syntax of the log file described
here to use mpr.  This information is provided for the curious and
for those who would like to write new tools to process the log file.

The log file consists of one line for each memory alloc/free request.
The first field of each line identifies the type of request
(malloc/free/realloc). The last few fields indicate the parameters to
the particular request.  The fields in between are the program counters
at the time of the request (the "call chain") - the program counters
are used to precisely track the source of each request.

notation:
()  -> grouping
*   -> repeat 0 or more times
+   -> repeat 1 or more times
"x" -> literal x

syntax:
<file>       ::= <line>*
<line>       ::= <mline> | <fline> | <rline>
<mline>      ::= "m:"<callchain><sz>":"<addr>            // malloc
<fline>      ::= "f:"<callchain><addr>                   // free
<rline>      ::= "r:"<callchain><sz>":"<oaddr>":"<naddr> // realloc
<callchain>  ::= (<pc>":")+
<pc>         ::= <num>
<sz>         ::= <num>
<addr>       ::= <num>
<oaddr>      ::= <num>
<naddr>      ::= <num>
<num>        ::= [0-9][0-9]*                             // decimal

Note that for malloc, <addr> may be 0 if the allocation fails and
for realloc, <newaddr> may be 0 if the re-allocation fails.

All numbers are stored in decimal format, rather than hexadecimal,
to make it easier to process them using awk(1).

--
