CTrace Manual

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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:

Type Description
int
0 success
1 failure

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.