Click here to Skip to main content
6,594,932 members and growing! (15,166 online)
Email Password   helpLost your password?
Languages » C / C++ Language » General     Beginner

A simple C++ function call stack trace utility

By Mockey Chen

How to record your function call stack for debug purpose.
C++, Windows, Dev
Posted:4 Feb 2006
Updated:10 Feb 2006
Views:73,702
Bookmarked:24 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
20 votes for this article.
Popularity: 3.88 Rating: 2.98 out of 5
5 votes, 25.0%
1
5 votes, 25.0%
2
6 votes, 30.0%
3
2 votes, 10.0%
4
2 votes, 10.0%
5

Introduction

What the article/code snippet does, why it's useful, the problem it solves etc.

Under UNIX/Linux platform, when program coredump, it generate a core file, we can analyse the core file and determine what's wrong in our program. The core file record the function call stack(e.g. under gdb you can use bt command to see backtrace), that is the mostly information for us to trouble shooting.

When I debug my program, I try to record the function call stack in program debug log to help me diagnose the program 's defect. Fortunately, C++ give us a simple way implement this.

Rational

Just use C++ constructor/destuctor semantic, we can make our own trace class. At the function entrance, we declare a local variable, it will be invoke constructor immediately, when leave the function, the local variable will be destroy and call destructor. That's all. what we need to do is implement a class's constructor and destructor. This rational is simple enough, but this way sometime can help us a lot.

The complete code as following:

// trace.hpp

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#include <stdarg.h>

#include <string>


#define CM_TRACE_FILE(trace_file)	cm::Trace::LogToFile(trace_file)

#define CM_TRACE_FUNC(func_name)    cm::Trace __CM_TRACE__(func_name, "()")
#define CM_TRACE_FUNC_ARG1(func_name, argfmt, arg)   \
            cm::Trace __CM_TRACE__(func_name, argfmt, arg)
#define CM_TRACE_FUNC_ARG2(func_name, argfmt, arg1, arg2)   \
            cm::Trace __CM_TRACE__(func_name, argfmt, arg1, arg2)
// more macros define....


namespace	cm
{
    class	Trace
    {
    public:
    	explicit Trace(char *func_name, const char* argsfmt, ...)
    	{
            char fmt[256] ={0};
            sprintf(fmt, "%s%s", func_name, argsfmt);
    	    va_list arglist;
    	    va_start(arglist, argsfmt);
    		LogMsg(depth_, depth_ * 2, fmt,  arglist);
    		va_end(arglist);
    		++depth_;
    	}

    	~Trace()
    	{
    		--depth_;
    	}

    	/// special the global log file.

    	void static LogToFile(const char *trace_file)
    	{
    		trace_file_ = trace_file;
    	}

    private:
    	void LogMsg(int depth, int align, const char *fmt, va_list args)
    	{
    		FILE	*fp = fopen(trace_file_.c_str(), "a+");
    		if (fp == NULL)
    		{
    			return;
    		}


    		time_t		curTime;
    		time(&curTime);

    		char	timeStamp[32] = { 0 };
    		strftime(timeStamp, sizeof(timeStamp), "%Y%m%d.%H%M%S", localtime(&curTime));

    		// only log the timestamp when the time changes

    		unsigned int len = fprintf( fp, "%s %*.*s> (%d)",
    				(last_invoke_time_ != curTime) ? timeStamp : "               ",
    				2 * depth,
    				2 * depth,
    				nest_,
    				depth);
    		last_invoke_time_ = curTime;
    		len += vfprintf(fp, fmt, args);
    		len += fwrite("\n", 1, 1, fp);
    		fflush(fp);
    		fclose(fp);
    	}

    private:
    	// the debug trace filename

    	static std::string	trace_file_;

    	// function call stack depth

    	static int			depth_;
    	static const char*  nest_;
    	static time_t       last_invoke_time_;
    };

    std::string Trace::trace_file_  = "";
    int         Trace::depth_       = 0;

    // arbitrarily support nesting 34 deep for no particular reason

    const char* Trace::nest_        = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ";
    time_t      Trace::last_invoke_time_ = 0;
}	// end namespace cm

#endif // CM_TRACE_20060209_HPP


Using the code

A brief desciption of how to use the article or code. The class names, the methods and properties, any tricks or tips.

Blocks of code should be wrapped in <pre> tags like this:

First you need call CM_TRACE_FILE() to special the debug log filename, then at funciton entrance call CM_TRACE(), here is a example.

#include "cm/trace.hpp"


void foo()
{
	CM_TRACE_FUNC("foo");
}

void bar(int x)
{
	CM_TRACE_FUNC_ARG1("bar", "(%d)", x);
	foo();
}

void foobar(int x, const char* s)
{
    CM_TRACE_FUNC_ARG2("foobar", "(%d, %s)", x, s);
    bar(789);
}

void foobar3(int x, int y, double z)
{
    CM_TRACE_FUNC_ARG3("foobar3", "(%d, %d, %f)", x, y, z);
    foobar(123, "4546");
}

int main()
{
    CM_TRACE_FILE("./trace.log");
    CM_TRACE_FUNC("main");
    foo();
    bar(23);
    foobar(33, "char");
    foobar3(12, 23, 34.45);
    return 0;
}

Then open `trace.log' use your favourite editor, at the end of file you will see as following:

20060211.132431 > (0)main()
                | > (1)foo()
                | > (1)bar(23)
                | | > (2)foo()
                | > (1)foobar(33, char)
                | | > (2)bar(789)
                | | | > (3)foo()
                | > (1)foobar3(12, 23, 34.450000)
                | | > (2)foobar(123, 4546)
                | | | > (3)bar(789)
                | | | | > (4)foo()

Conclusion

The rational in this article relate is simple, but we can simple code do useful things.

Revision History

v1.00 Feb 4, 2005. Mockey

  • Original article.

v1.01 Feb 11 2005. Mockey

  • Change fstream to FILE*.
  • Change stringstring to sprintf for more efficiency. Thanks Jon Wold's comment
  • Rename CM_TRACE to CM_TRACE_FUN and add CM_TRACE_FUN_ARGx macros.
  • Add feature to log the function call arguments.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Mockey Chen


Member
Mockey is a C++ programmer, experienced with C/C++ program under UNIX platform, his primarily research field is communication program for telecom. He works for one of china's biggest telecom equipment supplier now.

Mockey lives in ShenZhen, China with his lovely girlfriend. To contact Mockey, email at mockey.chen@gmail.com
Location: China China

Other popular C / C++ Language articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 19 of 19 (Total in Forum: 19) (Refresh)FirstPrevNext
Generalany idea for win32 C dll trace log. Pinmemberfredguo7:33 1 Mar '09  
Generalbug.. Pinmemberdheerajkhajuria7:17 8 Jul '07  
GeneralRe: bug.. PinmemberMockey Chen16:29 8 Jul '07  
GeneralCM_TRACE_FUNC_ARG3("foobar3", "(%d, %d, %s)", x, y, 100); PinmemberPham Thanh Toan7:57 3 Jan '07  
GeneralRe: CM_TRACE_FUNC_ARG3("foobar3", "(%d, %d, %s)", x, y, 100); PinmemberMockey Chen1:48 6 Jan '07  
Generalsprintf is declared as deprecated PinmemberDevianT (rus)14:27 21 Feb '06  
GeneralRe: sprintf is declared as deprecated PinmemberNemanja Trifunovic14:46 21 Feb '06  
GeneralRe: sprintf is declared as deprecated PinmemberDevianT (rus)21:21 21 Feb '06  
Generalsome advice Pinmemberthog17:27 14 Feb '06  
GeneralRe: some advice PinmemberGavriloaie Andrei23:54 26 Oct '07  
Generalscope logger PinmemberPaulius Maruška15:17 14 Feb '06  
GeneralNot a stack trace PinmemberScope17:08 12 Feb '06  
Generalminor comments ... PinmemberJon Wold6:44 7 Feb '06  
GeneralRe: minor comments ... PinmemberMockey Chen19:53 10 Feb '06  
GeneralAnd throwing in a couple of VC++ macros... PinmembereTurtle1:19 7 Feb '06  
GeneralRe: And throwing in a couple of VC++ macros... PinmemberMockey Chen5:32 7 Feb '06  
GeneralRe: And throwing in a couple of VC++ macros... PinmemberPavel Vozenilek19:54 13 Feb '06  
GeneralCool PinmemberFocusedWolf13:46 6 Feb '06  
GeneralRe: Cool PinmemberMockey Chen13:18 7 Feb '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 10 Feb 2006
Editor:
Copyright 2006 by Mockey Chen
Everything else Copyright © CodeProject, 1999-2009
Web13 | Advertise on the Code Project