커뮤니티 | 큐티/임베디드/큐토피아 | PODO | SDL | 마이크로윈도우 | 리눅스프로그래밍 | 기타 | 포인트순위 | 최근게시물최근게시물 RSS  
korone.net에 다루었으면 하는것은요?
 
 
 
 
 
108
1,062
3,878
3,768,781
  현재접속자 : 39 (회원 0)






배너 신청 문의

 
작성일 : 15-04-01 22:13
[QT/Embedded] C++ Exception을 활용한 런타임 콜스택 정보 얻기
 글쓴이 : korone
조회 : 5,460   추천 : 0  
   http://www.podovat.com/?p=432 [1126]
이글은 제가 podovat.com의 blog 올린글(http://www.podovat.com/?p=432)에서 퍼온것입니다.

1. 개요
동작중인 프로그램이 갑자기 오류를 발생하여 프로그램이 종료하는 문제를 찾기 위해서는 종료시점의 Call Stack을 확인하여 소스코드 상의 어디까지 수행을 하다 멈추었는지를 찾아서 디버깅을 해야 한다. 이를 위해서 Linux API중 backtrace함수는 호출 시점에 수행한 기록들을 알아낼 수 있는데, 이 함수를 프로그램 오류시 Exception이 발생될 때 호출하여, 그 기록을 파일로 저장하고, 이를 토대로 addr2line 유틸리티를 이용해서 실제 소스코드상의 위치를 알아낼 수 있다.

2. 구현
1과 같이 설명한 내용을 구현한 내용은 다음과 같으며 excpthandler.h 파일 이름으로 저장을 한다.
#ifndef [u]EXCPTHANDLER_H[/u]
#define [u]ECCPTHANDLER_H[/u]

#include <execinfo.h>
#include <signal.h>

#include <exception>
#include <iostream>
#include <fstream>

using namespace std;

class ExceptionTracer
{
    public:
        ExceptionTracer()
        {
            void * array[100];
            int nSize = backtrace(array, 100);
            char ** symbols = backtrace_symbols(array, nSize);

            // error file
            ofstream outFile;
            outFile.open("/program-error.log", ios::trunc);
            outFile << __DATE__ << "  " << __TIME__ << endl;
            for (int i = 0; i < nSize; i++)
            {
                cout << symbols[i] << endl;
                outFile << symbols[i] << endl;
            }

            free(symbols);
        }
};

template <class SignalExceptionClass> class SignalTranslator
{
    private:
        class SingleTonTranslator
        {
            public:
                SingleTonTranslator()
                {
                    signal(SignalExceptionClass::GetSignalNumber(), SignalHandler);
                }

                static void SignalHandler(int)
                {
                    throw SignalExceptionClass();
                }
        };

    public:
        SignalTranslator()
        {
            static SingleTonTranslator s_objTranslator;
        }
};

// An example for SIGSEGV
class SegmentationFault : public ExceptionTracer, public exception
{
    public:
        static int GetSignalNumber() {return SIGSEGV;}
};
SignalTranslator<SegmentationFault> g_objSegmentationFaultTranslator;

// An example for SIGFPE
class FloatingPointException : public ExceptionTracer, public exception
{
    public:
        static int GetSignalNumber() {return SIGFPE;}
};
SignalTranslator<FloatingPointException> g_objFloatingPointExceptionTranslator;

// An example for SIGILL
class IllegalInstructionException : public ExceptionTracer, public exception
{
    public:
        static int GetSignalNumber() {return SIGILL;}
};
SignalTranslator<IllegalInstructionException>
    g_objIllegalInstructionExceptionTranslator;

// An example for SIGTRAP
class TrapException : public ExceptionTracer, public exception
{
    public:
        static int GetSignalNumber() {return SIGTRAP;}
};
SignalTranslator<TrapException> g_objTrapExceptionTranslator;

class ExceptionHandler
{
    private:
        class SingleTonHandler
        {
            public:
                SingleTonHandler()
                {
                    set_terminate(Handler);
                }

                static void Handler()
                {
                    // Exception from construction/destruction of global variables
                    try
                    {
                        // re-throw
                        throw;
                    }
                    catch (SegmentationFault &)
                    {
                        cout << "SegmentationFault" << endl;
                    }
                    catch (FloatingPointException &)
                    {
                        cout << "FloatingPointException" << endl;
                    }
                    catch (IllegalInstructionException &)
                    {
                        cout << "IllegalInstructionException" << endl;
                    }
                    catch (TrapException &)
                    {
                        cout << "TrapException" << endl;
                    }
                    catch (...)
                    {
                        cout << "Unknown Exception" << endl;
                    }

                    //if this is a thread performing some core activity
                    abort();
                    // else if this is a thread used to service requests
                    // pthread_exit();
                }
        };

    public:
        ExceptionHandler()
        {
            static SingleTonHandler s_objHandler;
        }
};

// Before defining any global variable, we define a dummy instance
// of ExceptionHandler object to make sure that
// ExceptionHandler::SingleTonHandler::SingleTonHandler() is invoked
ExceptionHandler g_objExceptionHandler;

#endif

위의 구현 파일을 excpthandler.h 파일로 저장한다.

3. 예제
다음과 같은 예제를 만들어서 excpthandler.h 파일을 include 한다.
main.cpp
#include <QCoreApplication>
#include <QDebug>
#include "excpthandler.h"

int main(int argc, char** argv)
{
        QString* s1 = new QString("111");
        QString* s2 = new QString("222");

        QString* string[2] = { s1, s2 };

        for (int i=0; i<3; i++)
        {
                qDebug() << "string:" << *string[i];
        }

        return 0;
}

위의 코드를 컴파일 하기 위해서 다음과 같이 Project파일을 생성한다.
excpthandler.pro
TEMPLATE = app
QT += core
QT -= gui
ConFIG += debug
TARGET =
DEPENDPATH += .
INCLUDEPATH += .

# Input
SOURCES += main.cpp

command상에서 다음과 같이 compile을 한다.
$ qmake
$ make

4. 실행 및 디버깅
다음과 같이 프로그램을 실행하면 에러가 발생한다.
$ ./excpthandler
podo@ubuntu:~/excpthandler$ ./excpthandler
string: "111"
string: "222"
./excpthandler() [0x80497c4]
./excpthandler() [0x8049cff]
./excpthandler() [0x8049d8c]
[0xb7784400]
/usr/lib/i386-linux-gnu/libQtCore.so.4(_ZN11QTextStreamlsERK7QString+0x3a) [0xb75ae8aa]
./excpthandler() [0x8049752]
./excpthandler() [0x8049262]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0xb71ff4d3]
./excpthandler() [0x8049131]
SegmentationFault
Aborted (core dumped)

위의 표시 내용중 Segmentation Fault발생 이전까지 주소들이 표시가 되는데, 이 주소값을 이용해 소스코드 상의 어디인지 확인할 수 있다.
이를 위해 addr2line 프로그램을 이용해서 주소값을 입력하여 소스코드상의 위치를 확인한다.

podo@ubuntu:~/excpthandler$ addr2line -C -fe ./excpthandler 0x80497c4
ExceptionTracer
/home/podo/excpthandler/excpthandler.h:19
podo@ubuntu:~/excpthandler$ addr2line -C -fe ./excpthandler 0x8049cff
SegmentationFault
/home/podo/excpthandler/excpthandler.h:61
podo@ubuntu:~/excpthandler$ addr2line -C -fe ./excpthandler 0x8049d8c
SignalTranslator<SegmentationFault>::SingleTonTranslator::SignalHandler(int)
/home/podo/excpthandler/excpthandler.h:49
podo@ubuntu:~/excpthandler$ addr2line -C -fe ./excpthandler 0x8049752
QDebug::operator<<(QString const&)
/usr/include/qt4/QtCore/qdebug.h:112
podo@ubuntu:~/excpthandler$ addr2line -C -fe ./excpthandler 0x8049262
main
/home/podo/excpthandler/main.cpp:14

addr2line 을 이용해서 주소값을 차례대로 입력하다보면 main.cpp 의 14번째 라인에서 이상이 있음을 확인할 수 있다.
Qt Professional Service(http://podovat.com)



인라이… 15-04-02 11:09
 
구글의 breakpad 가 아마 비슷한 기능을 했던거 같네요.
 
 

Total 201
번호 제   목 글쓴이 날짜 조회 추천
201 [QT/Win32] MFC에서 Qt 사용하기 팁. (3) devilqoo 09-10 1570 0
200 [QT/X11] QML 모델을 C++ 코드로 구현하는 방법 중 하나 (1) 구름님 12-03 3901 0
199 [QT/X11] QWT for qt android (1) 구름님 03-07 5535 1
198 [QT/Win32] QtSingleApplication 이용하기 (1) starbig 01-18 5449 0
197 [QT/Win32] Qt 에서 Daum Maps Api geo [ 주소->좌표 변환 ] 사… starbig 01-15 6016 0
196 [QT/Win32] Qt에서 윈도우 서비스 이용하기, Qt Windows Servic starbig 01-15 4793 0
195 [QT/Embedded] QTcpSocket사용 시 플러그 뽑힘 증상 체크 방법 요원009 11-13 8762 0
194 [QT/Win32] QML 에서 CustomModule 을 import 하여 사용하기 tmdwn 05-18 5321 0
193 [QT/Embedded] Qt update함수/repaint함수 사용법좀 알려주세여.. (1) 잉농 05-14 5083 0
192 [QT/Embedded] C++ Exception을 활용한 런타임 콜스택 정보 얻기 (1) korone 04-01 5461 0
191 [QT/Embedded] Qt 5.4.1 raspberry Pi 프로그램 개발하기 (5) 구름님 03-31 18100 1
190 [QT/Win32] Qt 다국어 처리 (2) korone 03-17 10572 0
189 [QT/Win32] signal to signal devilqoo 02-13 4832 0
188 [QT/Win32] Qt x64 바이너리 제공 사이트 (1) 인라이… 02-12 4735 1
187 [QT/Embedded] 우분투 Qt5 크로스 컴파일 (14/11/26 2차 수정) (9) 김아무… 11-12 13386 0
186 [QT/Embedded] Qt 5.3.2에서 Mouse Double Click시 이벤트 문제 (2) korone 11-11 4865 0
185 [QT/Embedded] QtWinExtras korone 11-11 4827 0
184 [QT/Win32] Qt 코딩 스타일 (편집 편) (4) devilqoo 10-22 8740 0
183 [QT/Win32] Qt와 C++11 (2) devilqoo 10-12 8795 1
182 [QT/Win32] Qt 에서의 이벤트 처리 (5) devilqoo 10-09 8491 0
181 [QT/Win32] QList와 QVector의 비교. (2) devilqoo 10-02 6193 0
180 [QT/Win32] Qt에서 사용되는 컨테이너들을 정리해 보았습… (4) devilqoo 10-01 7027 0
179 [QT/X11] qmake DEFINES 변수에 공백문자가 포함된 값을 설… (1) 별님 09-25 4571 0
178 [QT/Win32] 데이터 압축 관련 qCompress(), qUncompress() (9) 구름님 09-16 5018 0
177 [QT/Win32] QML 로 One-Source Multi-Platform (iOS, Android) 실행 tmdwn 09-03 6481 0
176 [QT/Win32] QML 로 iOS Application 제작하기 tmdwn 09-02 6468 0
175 [QT/Win32] QML 로 Android Application 제작하기 (4) tmdwn 09-02 6866 2
174 [QT/X11] qt에서 메모리 조작하기. (2) 나무나… 07-25 6950 0
173 [QT/Win32] Q_DECLARE_FLAGS 매크로 (2) 구름님 07-11 5678 2
172 [QT/Win32] Q_PROPERTY 매크로 (6) 구름님 07-09 7640 2
 1  2  3  4  5  6  7  


About korone.net | Copyright 2003 korone.net. All rights reserved.