Sunday, September 20, 2015

Redirection of IO stream of C++

Sometimes, for programs written in C++, at the development stage, it's probably convenient to output the diagnosis information directly to console. And upon release, by the virtue of Macro, the diagnosis information can be eliminated. However for some daemon program, probably it still needs to output something if something wrong occurs. However simply turning on the Macro might not work since the TTY has been detached from standard output terminal or stand error terminal. The following are piece of work which can direct the IO stream from terminal to files. Hope it will be helpful under some occasion.


#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class MyLog
{
public:
    MyLog(char* path)
    {
        m_fp = fopen(path, "w");
    }
    ~MyLog()
    {        
        if (m_fp)
        {
            fclose(m_fp);
        }
    }

    void operator() (const string& s)
    {
        if (m_fp)
        {
            fprintf(m_fp, "%s\n", s.c_str());
            fflush(m_fp);
        }
    }

    void operator() (const char* fmt, ...)
    {
        if (m_fp)
        {
            char buf[256];
            va_list ap;

            memset(buf, 0, sizeof(buf));

            va_start(ap, fmt);
            buf[vsnprintf(buf, sizeof(buf), fmt, ap)] = '\0';
            va_end(ap);

            fputs(buf, m_fp);
            fflush(m_fp);
        }
    }
    
private:
    FILE* m_fp;
};

MyLog myLog("/opt/test.txt");

class Redirect
{
public:
    Redirect(MyLog& log) : m_log(log), m_oldCoutStreamBuf(cout.rdbuf())
    {
        cout.rdbuf(m_strCout.rdbuf());
    }
    ~Redirect()
    {
        m_log(m_strCout.str());
        cout.rdbuf(m_oldCoutStreamBuf);    
    }

private:
    MyLog& m_log;
    streambuf* m_oldCoutStreamBuf;
    ostringstream m_strCout;
};

void func1()
{
    Redirect r(myLog);
    cout << "in func1!" << endl;
}

void func2()
{
    Redirect r(myLog);
    cout << "in func2!" << endl;
    func1();
}

int main(int argc, char* argv[])
{
    Redirect* p = new Redirect(myLog);
    cout << "in main!" << endl;
    func2();
    delete p;
    cout << "You should see this!" << endl;
    return 0;
}

  

Utilize Python to control GDB

There's a good article details how to control GDB via Python instead of GDB script, please refer: http://www.linuxjournal.com/article/11027.

However due to time evolves, the Python scripts seems to stop working. The following is a modified one to compatible with the example giving in the article.


#!/usr/local/bin/python
from collections import defaultdict
# A dictionary of mutex:owner
mutexOwners = {}
# A dictionary of blocking mutex:(threads..)
threadBlockers = defaultdict(list)
# Print the threads
#print "Process threads : "
#gdb.execute("info threads")
print "Analysing mutexes..."
# Step through processes running under gdb
def get_frame(hint):
    
    frame = gdb.selected_frame()

    if hint == None:
        return frame
    elif type(hint) == int:
        i = 0
        while i < hint and frame != None:
            pre_frame = frame.older()
            if frame == pre_frame and frame < hint - 1:
                frame = None
                break
            else:
                frame = new_frame
            i += 1
    elif type(hint) == str:
        while frame != None:
            pre_frame = frame.older()
            if frame.name() == hint or pre_frame == frame:
                break
            else:
                frame = pre_frame
    return frame

for process in gdb.inferiors():

    # Step through each thread in the process
    for thread in process.threads():

        # Examine the thread -- is it blocking on a mutex?
        thread.switch()
        frame = get_frame("pthread_mutex_lock")
        
        if frame != None:
            frame.select()

            # Make a note of which thread blocks on which mutex
            mutex = int(gdb.parse_and_eval("$r8"))
            threadBlockers[mutex].append(thread.ptid[0])

            # Make a note of which thread owns this mutex
            if not mutex in mutexOwners:
                v = gdb.parse_and_eval("*$r8").cast(gdb.lookup_type("pthread_mutex_t"))
                mutexOwners[mutex] = v['__data']['__owner']

    # Print the results of the analysis
    for mutex in mutexOwners:
        print "  Mutex 0x%x :" % mutex
        print "     -> held by thread : %d" % mutexOwners[mutex]
        s = ["%d" % t for t in threadBlockers[mutex]]
        print "     -> blocks threads : %s" % ' '.join(s)