Книга: Embedded Linux Primer: A Practical, Real-World Approach
13.4.6. mtrace
13.4.6. mtrace
The mtrace package is a simple utility that analyzes and reports on calls to malloc(), realloc(), and free() in your application. It is easy to use and can potentially help spot trouble in your application. As with other userland tools we have been describing in this chapter, you must have the mtrace package configured and compiled for your architecture. mtrace is a malloc replacement library that is installed on your target. Your application enables it with a special function call. Your embedded Linux distribution should contain the mtrace package.
To demonstrate this utility, we created a simple program that creates dynamic data on a simple linked list. Each list item was dynamically generated, as was each data item we placed on the list. Listing 13-11 reproduces the simple list structure.
Listing 13-11. Simple Linear Linked List
struct blist_s {
struct blist_s *next;
char *data_item;
int item_size;
int index;
};
Each list item was dynamically created using malloc() as follows and subsequently placed at the end of the linked list:
struct blist_s *p = malloc(sizeof(struct blist_s));
Each variable-sized data item in the list was also dynamically generated and added to the list item before being placed at the end of the list. This way, every list item was created using two calls to malloc(), one for the list item itself, represented by struct blist_s just shown, and one for the variable data item. We then generated 10,000 records on the list containing variable string data, resulting in 20,000 calls to malloc().
To use mtrace, three conditions must be satisfied:
• A header file, mcheck.h, must be included in the source file.
• The application must call mtrace() to install the handlers.
• The environment variable MALLOC_TRACE must specify the name of a writeable file to which the trace data is written.
When these conditions are satisfied, each call to one of the traced functions generates a line in the raw trace file defined by MALLOC_TRACE. The trace data looks like this:
@ ./mt_ex:[0x80486ec] + 0x804a5f8 0x10
The @ sign signals that the trace line contains an address or function name. In the previous example, the program was executing at the address in square brackets, 0x80486ec. Using binary utilities or a debugger, we could easily associate this address with a function. The plus sign (+) indicates that this is a call to allocate memory. A call to free() would be indicated by a minus sign. The next field indicates the virtual address of the memory location being allocated or freed. The last field is the size, which is included in every call to allocate memory.
This data format is not very user friendly. For this reason, the mtrace package includes a utility[86] that analyzes the raw trace data and reports on any inconsistencies. In the simplest case, the Perl script simply prints a single line with the message "No memory leaks". Listing 13-12 contains the output when memory leaks are detected.
Listing 13-12. mtrace Error Report
$
mtrace ./mt_ex mtrace.log
Memory not freed:
-----------------
Address Size Caller
0x0804aa70 0x0a at /home/chris/temp/mt_ex.c:64
0x0804abc0 0x10 at /home/chris/temp/mt_ex.c:26
0x0804ac60 0x10 at /home/chris/temp/mt_ex.c:26
0x0804acc8 0x0a at /home/chris/temp/mt_ex.c:64
As you can see, this simple tool can help you spot trouble before it happens, as well as find it when it does. Notice that the Perl script has displayed the filename and line number of each call to malloc() that does not have a corresponding call to free() for the given memory location. This requires debugging information in the executable file generated by passing the -g flag to the compiler. If no debugging information is found, the script simply reports the address of the function calling malloc().