I'm developing some modules for an automation system written in C and I need to perform lots of work with hardware. And I see no simple way (like traditional) to debugging things instead of trace logs. So I'm looking for a good practice to log function calls. At least the sequence of calls and return values.
The way it is performed in application is quite straightforward and actually pollutes the code with irrelevant constructions like
int function (int param){
if(trace_level & LOG_FCALLS){
writelog("Entering function()");
}
/* something useful */
if(trace_level & LOG_FCALLS){
writelog("Exit from function()=%d", ret);
}
}
I decided to use a macro that will do all the dirty work. Now it looks like this
#define LOG_E(fn) const char *__fname=fn; printf("LOG: Entry to %s\n",__fname)
#define return(ret) printf("LOG: Exit from %s()=%d\n",__fname,ret)
int testFunc(){
LOG_E("testFunc");
/*do useful things */
return(ret);
}
I see the problems with this code
I'm overriding return statement, and it is requires to write return(ret) all the time instead of return ret. It is easy to forget this issue.
I'm defining string variable within my macro. I'm aware that __func__ macro exists in C99, but my compiler, unfortunately, doesn't support this macro or any other relevant macros.
How to log the values of function arguments?
I'm pretty sure that it is not a new problem and I'm not the first one who faced with it. I'm also aware about AOP thing, but the code instrumentation is not acceptable solution for my system and I haven't found any possibility to do it with my compiler.
So I'm looking for a good ideas how to implement tracing in the most elegant way.
My environment:
Legacy code, C, Watcom 10.x, real-time OS
The super-serious, professional way to do this is to make a separate debug/test project, which is separate from the production code entirely. It goes like this:
Make sure to have a backup/commit on the production code.
Make a hard-copy of the production code on the hard drive. This will become your test project.
Create a .txt log file where you write the full signature of each function you want to log, for example:
int function (int param)
float function2 (void)
...
Create a little PC program/script that takes the above .txt file as input, then searches through the source code for matching lines of function definitions. The PC program will then generate a new .c file based on the original code, where it inserts the debug logging code inside the desired functions, after { and before }. It will take a few hours of your time to make such a program.
Link your test project by using the modified source code created by your script.
The above method is how I do it myself on mission-critical software, where you have requirements from safety standards (MISRA, code coverage etc) saying that no code which is not executed in the final product is allowed.
This method ensures the integrity of the production code and guarantees that no accidental bugs are added to the program by the test/debug code. It also leaves the clutter of compile switches etc out of the production code. And you won't have any old debug code remains in your project that you forgot to delete (otherwise I always forget some snippet of debug code somewhere in my programs).
#if defined(DEBUG_BUILD)
# define START_FUNCTION if(trace_level & LOG_FCALLS){writelog("+++ %s()", __func__)
}
# define END_FUNCTION if(trace_level & LOG_FCALLS){writelog("--- %s()", __func__)
#elif defined (TIMING_BUILD)
# define START_FUNCTION WRITE_TIMED_LOG("+++")
# define END_FUNCTION WRITE_TIMED_LOG("---")
#else
# define START_FUNCTION
# define END_FUNCTION
#endif
int function (int param){
START_FUNCTION;
...
if(error_occurred) {
END_FUNCTION;
return errror_code;
}
...
END_FUNCTION;
return 42;
}
You might customize your compiler to handle that. You could use MELT (to customize your gcc compiler) if you are compiling with GCC.
Maybe you might customize openwatcom (or pay some OpenWatcom expert to do that)...
This works in MS Visual C. You will need different versions of the return macro for different data types (or none).
#include <stdio.h>
#define TRACING
#ifdef TRACING
#define LOG_E printf("Func: %s\n", __FUNCTION__);
#define LOG_R printf("Exit: %s\n", __FUNCTION__);
#define LOG_I(ival) printf("Exit: %s %d\n", __FUNCTION__, ival);
#else
#define LOG_E
#define LOG_R
#define LOG_I(ival)
#endif
int main(void){
int retval = 0;
LOG_E
printf("Hello world!\n");
LOG_I(retval)
return retval;
}
Output:
Func: main
Hello world!
Exit: main 0
Related
Original Question
What I'd like is not a standard C pre-processor, but a variation on it which would accept from somewhere - probably the command line via -DNAME1 and -UNAME2 options - a specification of which macros are defined, and would then eliminate dead code.
It may be easier to understand what I'm after with some examples:
#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif
If the command were run with '-DNAME1', the output would be:
#define ALBUQUERQUE "ambidextrous"
If the command were run with '-UNAME1', the output would be:
#define PHANTASMAGORIA "ghostly"
If the command were run with neither option, the output would be the same as the input.
This is a simple case - I'd be hoping that the code could handle more complex cases too.
To illustrate with a real-world but still simple example:
#ifdef USE_VOID
#ifdef PLATFORM1
#define VOID void
#else
#undef VOID
typedef void VOID;
#endif /* PLATFORM1 */
typedef void * VOIDPTR;
#else
typedef mint VOID;
typedef char * VOIDPTR;
#endif /* USE_VOID */
I'd like to run the command with -DUSE_VOID -UPLATFORM1 and get the output:
#undef VOID
typedef void VOID;
typedef void * VOIDPTR;
Another example:
#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
Ideally, I'd like to run with -UOLDUNIX and get the output:
#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
This may be pushing my luck!
Motivation: large, ancient code base with lots of conditional code. Many of the conditions no longer apply - the OLDUNIX platform, for example, is no longer made and no longer supported, so there is no need to have references to it in the code. Other conditions are always true. For example, features are added with conditional compilation so that a single version of the code can be used for both older versions of the software where the feature is not available and newer versions where it is available (more or less). Eventually, the old versions without the feature are no longer supported - everything uses the feature - so the condition on whether the feature is present or not should be removed, and the 'when feature is absent' code should be removed too. I'd like to have a tool to do the job automatically because it will be faster and more reliable than doing it manually (which is rather critical when the code base includes 21,500 source files).
(A really clever version of the tool might read #include'd files to determine whether the control macros - those specified by -D or -U on the command line - are defined in those files. I'm not sure whether that's truly helpful except as a backup diagnostic. Whatever else it does, though, the pseudo-pre-processor must not expand macros or include files verbatim. The output must be source similar to, but usually simpler than, the input code.)
Status Report (one year later)
After a year of use, I am very happy with 'sunifdef' recommended by the selected answer. It hasn't made a mistake yet, and I don't expect it to. The only quibble I have with it is stylistic. Given an input such as:
#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))
and run with '-UC' (C is never defined), the output is:
#if defined(A) && defined(B) || defined(D) && defined(E)
This is technically correct because '&&' binds tighter than '||', but it is an open invitation to confusion. I would much prefer it to include parentheses around the sets of '&&' conditions, as in the original:
#if (defined(A) && defined(B)) || (defined(D) && defined(E))
However, given the obscurity of some of the code I have to work with, for that to be the biggest nit-pick is a strong compliment; it is valuable tool to me.
The New Kid on the Block
Having checked the URL for inclusion in the information above, I see that (as predicted) there is an new program called Coan that is the successor to 'sunifdef'. It is available on SourceForge and has been since January 2010. I'll be checking it out...further reports later this year, or maybe next year, or sometime, or never.
I know absolutely nothing about C, but it sounds like you are looking for something like unifdef. Note that it hasn't been updated since 2000, but there is a successor called "Son of unifdef" (sunifdef).
Also you can try this tool http://coan2.sourceforge.net/
something like this will remove ifdef blocks:
coan source -UYOUR_FLAG --filter c,h --recurse YourSourceTree
I used unifdef years ago for just the sort of problem you describe, and it worked fine. Even if it hasn't been updated since 2000, the syntax of preprocessor ifdefs hasn't changed materially since then, so I expect it will still do what you want. I suppose there might be some compile problems, although the packages appear recent.
I've never used sunifdef, so I can't comment on it directly.
Around 2004 I wrote a tool that did exactly what you are looking for. I never got around to distributing the tool, but the code can be found here:
http://casey.dnsalias.org/exifdef-0.2.zip (that's a dsl link)
It's about 1.7k lines and implements enough of the C grammar to parse preprocessor statements, comments, and strings using bison and flex.
If you need something similar to a preprocessor, the flexible solution is Wave (from boost). It's a library designed to build C-preprocessor-like tools (including such things as C++03 and C++0x preprocessors). As it's a library, you can hook into its input and output code.
I'm looking for a (clean) way of writing a function definition and a function prototype without code duplication. Since DRY is well established as a good idea and hand coding prototypes in header files is a clear violation this seems like a reasonable requirement.
The example code below indicates a (crude) way of solving the problem with the preprocessor. It seems unlikely to be optimal, but does appear to work correctly.
Using separate files and duplication:
foo.h:
#ifndef FOO_H
#define FOO_H
// Normal header file stuff
int dofoo(int a);
#endif /* FOO_H */
foo.c:
#include "foo.h"
int dofoo(int a) {
return a * 2;
}
Using the C preprocessor:
foo.h:
#ifndef FOO_H
#define FOO_H
// Normal header file stuff
#ifdef PROTOTYPE // if incorrect:
// No consequences for this test case, but we lose a sanity check
#error "PROTOTYPE set elsewhere, include mechanism will fall over"
#endif
#define PROTOTYPE // if incorrect:
// "error: redefinition of 'dofoo'" in clang & gcc,
// referring to int dofoo() line in foo.c
#include "foo.c"
#undef PROTOTYPE //if incorrect:
// No warnings, but should trigger the earlier #error statement if
// this method is used in more than one file
#endif /* FOO_H */
foo.c:
#include "foo.h"
int dofoo (int a)
#ifdef PROTOTYPE // if incorrect:
// "error: redefinition of 'dofoo'" in clang & gcc,
// referring to int dofoo() line in foo.c
;
#else
{
return a * 2;
}
#endif
The mechanism is a bit odd - the .h file doesn't conventionally include the .c file! The include guard halts the recursion. It compiles cleanly and looks reasonable when run through a standalone preprocessor. Otherwise though, embedding preprocessor conditionals throughout the source doesn't look great.
There are a couple of alternative approaches I can think of.
Don't worry about the code duplication
Change to a language which generates the interface automatically
Use a code generator (e.g. sqlite's makeheaders)
A code generator would work but seems overkill as a solution for a minor annoyance. Since C has been around for somewhere over 25 years at this point there's hopefully a community consensus on the best path to take.
Thank you for reading.
edit: Compiler warnings with gcc 4.8.2 and clang 5.1
Messing up the macro statements produces fairly coherent compiler error messages. Missing an #endif (easily done if the function definition is long) produces "error: unterminated #else" or "error: unterminated conditional directive", both referring to the #ifdef line.
Missing #else means the code is no longer valid C. gcc "error: expected identifier or '(' before '{' token" and clang adds "expected function body after function declarator". Both point to the correct line number, but neither suggest an #else is missing.
Spelling PROTOTYPE wrong produces coherent messages if the result is fatal and no warning if the result doesn't matter. The compiler warnings aren't quite as specific as they can be when definition and declaration differ, but they're probably specific enough.
The generally accepted path is your option 1), to not worry and just write the declaration twice.
The repetition coming from prototypes is only a small percentage compared to the function implementations. Macro hacks like in your question quickly become unwieldy and provide little gain. The macro machinery ends up being just as much code as the original prototypes, only that it's now much harder to understand what's going on and that you'll get more cryptic error messages. The trivial to understand duplication gets replaced by about the same amount of much harder to understand trickery.
With normal prototypes the compiler will issue warnings when things don't match up, with such a macro base solution you get hard to understand errors if you forget an #endif or something else doesn't match up. For example any mention of foo.c in an error might be with or without PROTOTYPE defined.
I would like to take a look at it from another point of view. As I like to see DRY principle, it is meaningful for the code that provides logic, not taking it as repeating strings literally.
This way it would not touch declarations, as they introduce no logic. When you see few pieces of code, that do (as in perform some task) the same, just arguments change, then it should be avoided/refactored.
And this is what you actually do. You just introduced some new pre-processing logic into code, i.e. #ifdef PROTOTYPE... #else ... #endif, that you will repeat over and over just changing the prototype and the body. If you could wrap it up into something that does not enforce to repeat the branch I'd say it is somewhat ok.
But currently you really do repeat some logic in code, just to eliminate a multiple declarations, which is basically harmless in the context you provide. If you forget something the compiler will tell you something is mismatched. It's c.
I'd say your proposed approach violates it more, than repeated declarations.
I have an almost identical question as How to add code at the entry of every function? but for C:
As I'm maintaining someone else's large undocumented project, I wish to have code similar to
static C0UNT_identifier_not_used_anywhere_else = 0;
printf("%s%s:%d#%d", __func__, strrchr(__FILE__,'/'), __LINE__, ++C0UNT_identifier_not_used_anywhere_else);
to run on entry of every function, so that I
have a log of what calls what, and
can tell, on which nth call to a function it breaks.
The existing code comprises hundreds of source files, so it is unfeasible to put a macro e.g.
#define ENTRY_CODE ...
...
int function() {
ENTRY_CODE
...
}
in every function. I am also not using DevStudio, Visual Studio or other compiler providing __cyg_profile_func_enter or such extensions.
Optionally, I'd like to printf the return value of each function on exit in a similar style. Can I do that too?
Since you have tagged with gcc it has the -finstrument-functions option:
Generate instrumentation calls for entry and exit to functions. ...
Is there any way to programmatically mock a function for a embedded c application, running on linux. In below example I want to mock main to call someBlah instead of someFunc in run-time.
#include <stdio.h>
void someFunc( void )
{
printf("%s():%d\n",__func__,__LINE__);
}
void someBlah( void )
{
printf("%s():%d\n",__func__,__LINE__);
}
int main(void)
{
someFunc();
}
The program will be executing from ram in Linux so text segment should be modifiable. I know GDB works on some similar concept where breakpoints code locations are replaced by trap instructions.
Sure, just make a table of function pointers.
#define BLAH 0
#define FOO 1
void (*table_function[])(void) = {someBlah, someFoo};
If they all have the same interface and return type, you can just switch them by switching table entries.
Then you call a function by performing
table_function[BLAH]();
If you want to swap a function, just say
table_function[BLAH] = otherBlah;
Also: don't do this unless you are writing some kind of JIT-compiling environment or a VM, usually you don't need such constructs and if you need them you are probably having a bad architecture day.
Although if you're experienced in OO design you can design polymorphic constructs in C that way (ignore this if that doesn't make sense).
You could always make some part of the text segment modifiable by an appropriate call to mprotect and overwrite some code with your own (e.g. by generating machine code with libjit, GNU lightning, ... or manually).
But using function pointers is a cleaner way of doing that.
If the functions are inside a shared library, you could even overwrite its Procedure Linkage Table (see also the ABI spec, which depends upon the architecture - here is one for ARM)
There are a few mocking frameworks for C.
At work, we've had some success with cgreen but we did have to make changes to its internals. Luckily, it's quite small, and so relatively easy to extend. An alternative that looks good, but I haven't worked with, is a combination of Unity and CMock.
On the general topic of unit testing embedded C code, I highly recommend Test Driven Development for Embedded C.
Another way I have done this is:
#include <stdio.h>
#define DEBUG
void someFunc( void )
{
#ifndef DEBUG
printf("%s():%d\n",__func__,__LINE__);
#else
printf("%s():%d\n",__func__,__LINE__);
#endif
}
int main(void)
{
someFunc();
}
Take a look at CMocka, there is an article about mocking on LWN: Unit testing with mock objects in C
by design, in the environment I'm working right now I can't use a debugger to try to detect bugs, so pretty much always when I need to debug a functionality I end up outputting some info.
To do that I've done the following:
#ifdef DEBUG
#define printd(x) printf x
#else
#define printd(x)
#endif
So when I need to print some debug info I use printd() instead of printf().
The problem I've found is that I need a leveled system, there are messages that may be important in a determined debug level, but irrelevant when debugging other parts of the code.
So my question is, how can I implement a leveled debug system? I value simplicity, I mean, I prefer my actual system than needing a lot of code or confusing code when using it. Something like printd(level, format, ...) would be awesome.
Sure, there are more elegant ways to do this, of course, but this works just fine
#ifdef DEBUG
extern int g_debuglevel;
#define printd(level, x) (level <= g_debuglevel) ? 0 : printf x
#else
#define printd(level, x)
#endif
Although personally I prefer this
#ifdef DEBUG
extern void printdf(level, fmt, ...);
#define printd printfd
#else
#define printd
#endif
where printdf is a function that tests the level and then calls vprintf passing along the fmt and va_args.
See the answers to:
C #define macro for debug printing
Multi-file C program: how best to implement optional logging
These will give you a lot of pointers on what to do.
If you want to go the extra step and log your level debug statements they you could try log4c.
http://log4c.sourceforge.net/
in the printfd function described above, you can also check for an environment variable say DEBUG_LOG_LEVEL to dynamically switch on and off your logging.
I used a similar technique to implement a lightweight leveled logging library for an embedded linux environment.
Also for an example of log4c -
http://log4c.sourcearchive.com/documentation/1.2.1/helloworld_8c-source.html
Thanks to google search :)