1 Overview
|
1.1 CTrace Manual Version
|
Version: 1.2
Author: Cal McPherson
Comments: Initial revision of the document.
|
1.2 What is CTrace?
|
CTrace is a fast, lightweight trace/debug C library.
It was specifically written for use in a multi-threaded
application, though it will work just fine
in a single threaded C application.
A trace/debug library has an interface of macros or functions
which outputs the contents of program variables as the application
is running. The trace calls may be made at certain user-defined levels.
It may also be required to have
trace functions only called on a particular thread or logical unit
of the application.
Isn't that what debuggers are for? Well, yes,
though debuggers can be kind of tricky to use when an application
is running across multiple threads. Also, once an application is
deployed, for example on an embedded system, using debuggers becomes
impractical. In this case, a remote protocol could turn tracing on
for parts of the application, and the results may be returned either
as a stream, or output to a file on the remote system, and collected
via ftp.
|
1.3 CTrace Features
|
- Fast, ligthweight tracing
- Support for turning tracing on and off as required
- Support for turning trace levels on and off independantly
- Support for adding and removing trace threads
- Ability to turn individual thread traces on and off in isolation
- Ability to trace logical software units in isolation
CTrace is distributed under the GNU General Public License and is free
for use
|
2 Reference
|
2.1 Trace Library Initialisation and Cleanup
|
Before the trace library is used, it must first be initialised
by calling either the TRC_INIT_DEFAULT or the TRC_INIT macro.
Initialisation should normally take place upon startup of the
application, for example after entry of the program's main() function.
Note there is a difference between enabling and disabling tracing
and turning tracing on and off.
The trace library is made up of
macros which call functions in the trace library. In a deployed
system we do not want these functions being called if
we are not currently tracing anything.
Disabling the trace libraries prevents the underlying
calls to the trace library. It is recommended to initialise the
trace library with the TRC_DISABLED flag for normal(non-traced)
running of your application.
Because the trace library allows multiple threads and for threads
to be traced in isolation, it is neccessary to have an additional
flag for turning tracing on and off at the thread level. For this
reason, if you are using the trace library in a single-threaded
application, you need to both enable tracing with the TRC_ENABLED
flag, and turn tracing on with the TRC_ON flag for tracing to occur.
Finally, immediately prior to exiting your program you should call
TRC_END() to cleanup data structures and close threads associated
with the trace library.
|
2.1.1 TRC_INIT_DEFAULT()
|
Arguments: void
Return Value:
Description:
Initialise the trace library for use with default settings.
Example:
TRC_INIT_DEFAULT();
Initialise trace library with the following values:
- _STDOUT - send output to standard output stream
- TRC_DISABLED - disable tracing
- TRC_ON - turn tracing on for all threads
- TRC_ERR - turn on error tracing only for all trace levels
- 100 - reserve space for 100 logical software units
- TRC_SERV_OFF - run tracing inside the thread being traced
|
2.1.2 TRC_INIT(a,b,c,d,e)
|
Arguments:
Name |
Type |
Description |
a |
const char * |
Default output stream for tracing:
NULL |
standard output |
"stdout" |
standard output |
"stderr" |
standard error |
"filename" |
output to "filename" |
|
b |
t_enable_t |
Trace enabled flag |
c |
t_on_t |
Trace on/off flag |
d |
t_level_t |
Trace levels to default to |
e |
unsigned int |
Number of logical software units to allocate space for |
f |
t_server_t |
Run trace as separate server thread |
Return Value:
Description:
Initialise the trace library for use.
Example:
TRC_INIT(NULL, TRC_ENABLED, TRC_ON, TRC_ALL, 100, TRC_SERV_OFF);
Initialise trace library with the following values:
- NULL - send output to standard output stream
- TRC_ENABLED - enable tracing
- TRC_ON - turn tracing on for all threads
- TRC_ALL - turn tracing on for all trace levels
- 100 - allocate space for 100 logical software units
- TRC_SERV_OFF - run tracing inside the thread being traced
|
2.1.1 TRC_END()
|
Arguments: void
Return Value: void
Description:
Cleanup trace library data structures and threads.
Example:
TRC_END();
|
2.2 Trace Calls
|
The trace calls are the meat and potatoes of the CTrace library.
They send the tracing information to the output stream.
TRC_ENTER() displays the procedure or function name and the
values of the arguments passed into it as parameters. It
should be called immediately upon entering a procedure or function.
TRC_RETURN() displays the function return value and then
performs function return. TRC_VOID_RETURN() displays and performs
procedure return.
TRC_TRACE() is used to display any general trace information, in
the format of keyword/value pairs.
Finally, TRC_ERROR displays error information, once again in the
format of keyword/value pairs. TRC_ERROR calls will occur when
the TRC_ERR tlevel_t flag is set.
|
2.2.1 TRC_ENTER(a,b,c)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
t_level_t |
trace level |
c |
char * |
Formatted vararglist of fn argument values |
Return Value: void
Description:
Write trace enter function/procedure line to output stream.
Argument <c> takes the form ("%d, %s", 1, "string") as
per the vararglist format of fprintf and printf C functions.
Example:
void myfunction(int myfn_arg1, char *myfn_arg2){
TRC_ENTER(UNIT_FOO, TRC0, (%d, %s", myfn_arg1, myfn_arg2));
...
Show that "myfunction" has been entered with argument values "myfn_arg1", "myfn_arg2".
|
2.2.2 TRC_RETURN(a,b,c,d)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
t_level_t |
trace level |
c |
char * |
Formatted vararglist showing return value |
d |
void |
Return value |
Return Value: void
Description:
Write trace return from function line to output stream.
Argument <c> takes the form ("%d, %s", 1) as
per the vararglist format of fprintf and printf C functions.
Note this function performs function return. The function
return value is passed as argument <d> to the macro.
Example:
...
TRC_RETURN(UNIT_FOO, TRC0, (%d", retval), retval);
}
Show that function return has taken place returning value "retval". Also
performs function return.
|
2.2.3 TRC_VOID_RETURN(a,b)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
t_level_t |
trace level |
Return Value: void
Description:
Write trace return from procedure line to output stream.
Note this macro performs procedure return.
Example:
...
TRC_VOID_RETURN(UNIT_FOO, TRC0);
}
Show that procedure return has taken place. Also
performs procedure return.
|
2.2.4 TRC_PRINT(a,b,c,d)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
t_level_t |
trace level |
c |
char * |
Formatted vararglist of fn argument values |
Return Value: void
Description:
Write trace print line to output stream.
Argument <c> takes the form ("%d, %s", 1, "string") as
per the vararglist format of fprintf and printf C functions.
Example:
TRC_PRINT(UNIT_FOO, TRC0, ("i=%d", 0));
|
2.2.5 TRC_ERROR(a,b)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
char * |
Formatted vararglist of fn argument values |
Return Value: void
Description:
Write trace print line to output stream.
Argument <b> takes the form ("%d, %s", 1, "string") as
per the vararglist format of fprintf and printf C functions.
Trace level flag TRC_ERR needs to be set for TRC_ERROR output
lines to be send to the output stream.
Example:
TRC_ERROR(UNIT_FOO, ("s=%s", "your rooted"));
|
2.3 Turn Tracing On/Off
|
TRC_ENABLE() and TRC_DISABLE() are used to disable and enable
tracing. Upon entry to every trace macro a flag is checked to
determine if tracing is enabled. If tracing is enabled, the
underlying trace function and procedure calls are made. Tracing
may or may not occur dependant upon other trace flags, but
this is expensive and undesirable if tracing is not being used.
Keep tracing disabled by default.
The trace library allows turning tracing on and off at the
thread level. Each thread can be turned on and off in isolation.
In addition, the macros TRC_TURN_ON() and TRC_TURN_OF() provide
blanket calls to turn tracing on and off for all trace threads.
Somehow, a trace thread needs to have tracing turned on in order
for trace output calls to send trace information to the output
stream.
|
2.3.1 TRC_ENABLE()
|
Arguments: void
Return Value: void
Description:
Enable tracing calls. Causes trace output macro calls(
TRC_ENTER, TRC_RETURN, TRC_VOID_RETURN, TRC_PRINT, TRC_ERROR)
to call their underlying library functions.
Tracing must also be turned on for the traced
thread with TRC_TURN_ON(all threads) or TRC_TURN_THREAD_ON macro for
tracing to occur.
Example:
TRC_ENABLE();
|
2.3.2 TRC_DISABLE()
|
Arguments: void
Return Value: void
Description:
Disable tracing calls. Stops trace output macro calls(
TRC_ENTER, TRC_RETURN, TRC_VOID_RETURN, TRC_PRINT, TRC_ERROR)
calling their underlying library functions. If a real-time
system(or any system) is not being traced, we do not want
redundant function calls taking up processor time. For this
reason, you should set TRC_DISABLED flag as default in the TRC_INIT()
macro for normal(non-traced) program execution.
Example:
TRC_DISABLE();
|
2.3.3 TRC_TURN_ON()
|
Arguments: void
Return Value: void
Description:
Turn tracing on for all trace threads. If tracing is not turned
on for a thread(this includes the main() program thread)
tracing will not occur.
Example:
TRC_TURN_ON();
|
2.3.4 TRC_TURN_OFF()
|
Arguments: void
Return Value: void
Description:
Turn tracing off for all trace threads.
Example:
TRC_TURN_OFF();
|
2.4 The Trace Output Stream
|
Use the TRC_FILE() macro to set the trace output stream for
the trace calls. Trace information can be directed to stdout(default),
stderr, or to a file.
|
2.4.1 TRC_FILE(a)
|
Arguments:
Name |
Type |
Description |
a |
const char * |
trace output stream:
NULL |
standard output |
"stdout" |
standard output |
"stderr" |
standard error |
"filename" |
output to "filename" |
|
Return Value:
Description:
New output stream for trace library becomes <a>
Example:
TRC_FILE("myfile.trc");
Send all trace output to the file "myfile.trc".
|
2.5 Working With Trace Threads
|
CTrace provides independant tracing for multiple program
threads. Before tracing can occur on any thread(including
the main() program thread in a single threaded application)
the thread needs to be added to the trace library using the
TRC_ADD_THREAD() macro. It can later be removed using the
TRC_REMOVE_THREAD() macro.
Once a thread has been added to the trace library, it can
have tracing turned on and off for it using the
TRC_TURN_THREAD_ON() and TRC_TURN_THREAD_OFF() macros.
|
2.5.1 TRC_ADD_THREAD(a,b)
|
Arguments:
Name |
Type |
Description |
a |
const char * |
Trace output thread name |
b |
tid_t |
Thread id |
Return Value:
Description:
Add thread with display name <a> and id <b> to trace library.
If <b> equals 0 thread id defaults to the calling thread of this macro.
The CTrace library keeps a data structure in memory for each tracable thread.
For this reason, even the main() program
thread must be added with TRC_ADD_THREAD(argv[0], 0).
Example:
TRC_ADD_THREAD("thread1", 0);
Add the calling thread of the macro to the trace library.
Refer to it as "thread1" in the output stream.
|
2.5.2 TRC_REMOVE_THREAD(a)
|
Arguments:
Name |
Type |
Description |
a |
tid_t |
Thread id |
Return Value:
Description:
Remove thread with id <a> from trace library.
If <a> equals 0 thread id defaults to the calling thread of this macro.
Example:
TRC_REMOVE_THREAD(0);
Remove the calling thread of the macro from the trace library.
|
2.5.3 TRC_TURN_THREAD_ON(a)
|
Arguments:
Name |
Type |
Description |
a |
tid_t |
Thread id |
Return Value:
Description:
Turn tracing on for thread with id <a>.
If <a> equals 0 thread id defaults to the calling thread of this macro.
Example:
TRC_TURN_THREAD_ON(0);
Turn tracing on for the calling thread of the macro.
|
2.5.4 TRC_TURN_THREAD_OFF(a)
|
Arguments:
Name |
Type |
Description |
a |
tid_t |
Thread id |
Return Value:
Description:
Turn tracing off for thread with id <a>.
If <a> equals 0 thread id defaults to the calling thread of this macro.
Example:
TRC_TURN_THREAD_OFF(0);
Turn tracing off for the calling thread of the macro.
|
2.6 Working With Trace Levels
|
Every trace output call(TRC_ENTER, TRC_RETURN, TRC_VOID_RETURN,
TRC_TRACE) except TRC_ERROR is passed a tlevel_t argument.
This argument tells the trace library which level(s) the
trace output call should operate on. TRC_ERROR operates
on tlevel_t TRC_ERR by default.
Therefore, when the program starts up, every trace output
call embedded in it has a predefined hard-coded trace
level(s). TRC_SET_LEVEL(), TRC_ADD_LEVEL() and TRC_REMOVE_LEVEL()
macros effectively activate or deactivate these tracing levels.
The "SET" macros perform a blanket overwrite of all currently
activated levels with the new level(s) passed in as the parameter.
The "ADD" and "REMOVE" macros enable finer granularity by retaining
any existing levels that dont confict with the level(s) passed in
as the parameter.
|
2.6.1 TRC_SET_LEVEL(a)
|
Arguments:
Name |
Type |
Description |
a |
tlevel_t |
trace level(s) |
Return Value:
Description:
Set level <a> in all added trace threads.
<a> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings will be made obsolete.
Example:
TRC_SET_LEVEL(TRC1|TRC2);
Set tracing at levels TRC1 and TRC2.
|
2.6.2 TRC_ADD_LEVEL(a)
|
Arguments:
Name |
Type |
Description |
a |
tlevel_t |
trace level(s) |
Return Value:
Description:
Add level <a> to all added trace threads.
<a> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings not conflicting with
<a> will be retained.
Example:
TRC_ADD_LEVEL(TRC4);
Add level TRC4 to existing tracing levels.
|
2.6.3 TRC_REMOVE_LEVEL(a)
|
Arguments:
Name |
Type |
Description |
a |
tlevel_t |
trace level(s) |
Return Value:
Description:
Remove level <a> from all added trace threads.
<a> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings not conflicting with
<a> will be retained.
Example:
TRC_REMOVE_LEVEL(TRC4);
Remove level TRC4 from existing tracing levels.
|
2.6.4 TRC_SET_THREAD_LEVEL(a,b)
|
Arguments:
Name |
Type |
Description |
a |
tlevel_t |
trace level(s) |
b |
tid_t |
thread id |
Return Value:
Description:
Set level <a> in thread <b>.
<a> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings will be made obsolete.
If <b> equals 0 thread id defaults to the
calling thread of this macro.
Example:
TRC_SET_THREAD_LEVEL(TRC_ALL, 0);
Set tracing at all levels for the calling thread of this macro.
|
2.6.5 TRC_ADD_THREAD_LEVEL(a,b)
|
Arguments:
Name |
Type |
Description |
a |
tlevel_t |
trace level(s) |
b |
tid_t |
thread id |
Return Value:
Description:
Add level <a> to thread <b>.
<a> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings not conflicting with
<a> will be retained.
If <b> equals 0 thread id defaults to the
calling thread of this macro.
Example:
TRC_ADD_THREAD_LEVEL(TRC4, 23);
Add level TRC4 to existing tracing levels in thread with id 23.
|
2.6.6 TRC_REMOVE_THREAD_LEVEL(a,b)
|
Arguments:
Name |
Type |
Description |
a |
tlevel_t |
trace level(s) |
b |
tid_t |
thread id |
Return Value:
Description:
Remove level <a> from thread <b>.
<a> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings not conflicting with
<a> will be retained.
If <b> equals 0 thread id defaults to the
calling thread of this macro.
Example:
TRC_REMOVE_THREAD_LEVEL(TRC4, 23);
Remove level TRC4 from existing tracing levels in thread with id 23.
|
2.7 Performing a Software Unit Trace
|
Every trace output call
is passed an unsigned int argument.
This argument represents a user-defined logical software unit of
the program.
Therefore, when the program starts up, every trace output
call belongs to a software unit(unless this field is set to 0).
Because the value 0 is reserved to indicate software unit tracing
is not required, legal identifier values must start from 1. CTrace needs
to be told how many software units are required during initialisation so it
can allocate the appropriate memory. The number
of software units required is passed to TRC_INIT(), or defaults to 100
if using TRC_INIT_DEFAULT().
TRC_TURN_UNIT_ON(), TRC_TURN_UNIT_OFF()
macros effectively activate or deactivate tracing calls for the software
unit passed in as the parameter.
TRC_SET_UNIT_LEVEL(), TRC_ADD_UNIT_LEVE(), TRC_REMOVE_UNIT_LEVEL()
macros provide a finer level of granularity over unit tracing.
|
2.7.1 TRC_TURN_UNIT_ON(a)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
Return Value:
Description:
Turn tracing on for <a>.
A logical software unit will share the same
tunit_t variable. When a tunit_t flag is set,
tracing of this local software unit may be performed
in isolation.
Example:
TRC_TURN_UNIT_ON(UNIT_FOO);
Turn tracing on for the logical software unit sharing
the identifier UNIT_FOO).
|
2.7.2 TRC_TURN_UNIT_OFF(a)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
Return Value:
Description:
Turn tracing off for <a>.
A logical software unit will share the same
tunit_t variable. When a tunit_t flag is set,
tracing of this software unit may be performed
in isolation.
Example:
TRC_TURN_UNIT_OFF(UNIT_FOO);
Turn tracing off for the logical software unit sharing
the identifier UNIT_FOO.
|
2.7.3 TRC_SET_UNIT_LEVEL(a,b)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
tlevel_t |
trace level(s) |
Return Value:
Description:
Set level <b> in <a>.
<b> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings will be made obsolete.
Example:
TRC_SET_UNIT_LEVEL(UNIT_FOO, TRC_ERROR);
Set tracing to show TRC_ERROR calls only
for the logical software unit sharing
the identifier UNIT_FOO.
|
2.7.4 TRC_ADD_UNIT_LEVEL(a,b)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
tlevel_t |
trace level(s) |
Return Value:
Description:
Add level <b> to <a>.
<b> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings not conflicting with <b&bt
will be retained.
Example:
TRC_ADD_UNIT_LEVEL(UNIT_FOO, TRC4);
Add tracing level TRC4 to the existing levels
for the logical software unit sharing
the identifier UNIT_FOO.
|
2.7.5 TRC_REMOVE_UNIT_LEVEL(a,b)
|
Arguments:
Name |
Type |
Description |
a |
unsigned int |
software unit identifier |
b |
tlevel_t |
trace level(s) |
Return Value:
Description:
Remove level <b> from <a>.
<b> may be any legal tlevel_t including an Ored
combination of any legal tlevel_t, eg TRC1|TRC2.
Any previous level settings not conflicting with <b&bt
will be retained.
Example:
TRC_REMOVE_UNIT_LEVEL(UNIT_FOO, TRC4);
Remove tracing level TRC4 from the existing levels
for the logical software unit sharing
the identifier UNIT_FOO.
|