![]() |
Languages »
C / C++ Language »
General
Beginner
A simple C++ function call stack trace utilityBy Mockey ChenHow to record your function call stack for debug purpose. |
C++, Windows, Dev
|
||||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
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.
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
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()
The rational in this article relate is simple, but we can simple code do useful things.
v1.00 Feb 4, 2005. Mockey
v1.01 Feb 11 2005. Mockey
General
News
Question
Answer
Joke
Rant
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 |