получение call stack при падении программы
От: betauser  
Дата: 26.12.04 18:32
Оценка:
вот к примеру у меня упала прога.
(ну допустим обратились вне адресного пространства)
мне нужно получить call stack того места где это произошло.
при этом это release версия приложения. (и мы не в debug'e сидим)
как это реализовать?

вариант наставить в каждой функции exception не подходит.


26.12.04 22:15: Перенесено из 'C/C++'
Re: получение call stack при падении программы
От: adontz Грузия http://adontz.wordpress.com/
Дата: 26.12.04 19:42
Оценка:
Здравствуйте, betauser, Вы писали:

http://www.codeproject.com/cpp/exception.asp
A journey of a thousand miles must begin with a single step © Lau Tsu
Re: получение call stack при падении программы
От: tarkil Россия http://5209.copi.ru/
Дата: 27.12.04 03:57
Оценка:
Здравствуйте, betauser, Вы писали:

B>мне нужно получить call stack того места где это произошло.

B>при этом это release версия приложения. (и мы не в debug'e сидим)

http://www-d0.fnal.gov/cgi-bin/cvsweb.cgi/seh/Source/#dirlist
Скачай отсюда stackwalk.cpp & .h

Там функция раскрутки стека по структуре CONTEXT, описывающей некоторую точку выполняемого кода. Когда вылетает SEH-исключения (типа того же access violation) можно получить CONTEXT точки, где оно вылетело (см. в MSDN GetExceptionЧегоТоТам), а потом натравить на эту структуру функцию ShowStack, которая выведет данные на стандартный выход. Не проверял, но полагаю, что даже в release для стабильной работы надо отключить оптимизацию стекового фрейма (/Oy-). Чтобы вместо адресов видны были символические имена функций, надо так же скомпилить release с дебажной базой данных (в отдельных pdb-файлах, конечно, они размер не увеличивают).
--
wbr, Peter Taran
Re: получение call stack при падении программы
От: assad Россия  
Дата: 27.12.04 07:14
Оценка:
Hello betauser,

b> вот к примеру у меня упала прога.

b> (ну допустим обратились вне адресного пространства)
b> мне нужно получить call stack того места где это произошло.
b> при этом это release версия приложения. (и мы не в debug'e сидим)
b> как это реализовать?


Для релиза мало без опции stack frame?
hаскрутить стек будет затруднительно.
Учитывая, что алгоритм call stack такой.

[code]
void CallStack(DWORD _eip, DWORD _ebp /*исходное*/)
{
DWORD pc = _eip;
PDWORD pFrame = reinterpret_cast<PDWORD>(_ebp);
PDWORD pPrevFrame;

do
{
pc = pFrame[1]; //eip
pPrevFrame = pFrame;
pFrame = reinterpret_cast<PDWORD>(pFrame[0]);

if ( reinterpret_cast<DWORD>(pFrame ) & 3)
break;

if ( pFrame <= pPrevFrame )
break;

if ( IsBadWritePtr(pFrame, sizeof(PVOID)*2) )
break;

} while(1);
}
[\code]


--
Best regards,
assad mailto:assad77@gmail.com
Posted via RSDN NNTP Server 1.8
Re[2]: получение call stack при падении программы
От: assad Россия  
Дата: 27.12.04 07:21
Оценка:
a> Для релиза мало без опции stack frame?
Имелось в виду что при компиляции должна происходить
генерация кадра стэка.
По умолчанию для MSVC++ это не делается.
Сильно это прогу не замедлит.
Posted via RSDN NNTP Server 1.8
Re: получение call stack при падении программы
От: kmn Украина  
Дата: 27.12.04 12:09
Оценка: 15 (2) :)
Здравствуйте, betauser, Вы писали:

B>вот к примеру у меня упала прога.

B>(ну допустим обратились вне адресного пространства)
B>мне нужно получить call stack того места где это произошло.
B>при этом это release версия приложения. (и мы не в debug'e сидим)
B>как это реализовать?

B>вариант наставить в каждой функции exception не подходит.


Вот что мы в своих проектах используем.


//    xxstackguard.h

#ifndef XX_STACK_GUARD_H
#define XX_STACK_GUARD_H

#include <exception>

#ifdef STACKGUARG_EXPORTS
    #define XX_PUBLIC    XX_EXPORT
#else
    #define XX_PUBLIC    XX_IMPORT
#endif 

// forward declaration
    class IxxStackGuardManager;

EXTERN_C XX_PUBLIC IxxStackGuardManager * xxGetStackGuardManager();

class IxxStackGuardManager
{
public:
    virtual void Push(const char * lpszReport) = 0;
    virtual void Clear() = 0;
    virtual const char * Report() = 0;
};

class CxxStackGuard
{
    const char* m_lpszFunction;
public:
    inline CxxStackGuard(const char* lpszFunction)
        : m_lpszFunction(lpszFunction)
        {
        }

    inline ~CxxStackGuard()
        {
    #if (_MSC_VER >= 1300)
        #ifdef _STLPORT_VERSION
            if (__uncaught_exception())
        #else
            if (std::uncaught_exception())
        #endif
    #else
        #error uncaught_exception is not supported
    #endif 
            {
                IxxStackGuardManager * pManager = xxGetStackGuardManager();
                pManager->Push(m_lpszFunction);
            }
        }
};


////////////////////////////////////////////////////////////////////////////
// несколько вспомогательных макросов.

#define XX_STACK_GUARD\
        CxxStackGuard __xxStackGuard__FUNCTION__);\

#define XX_STACK_GUARD_BLOCK(x)\
    CxxStackGuard __xxStackGuardBlock(#x);\


////////////////////////////////////////////////////////////////////////////
// пытались сформировать имя переменной на базе номера строки, но это работает 
// только при определенных настройках проекта (VC7.x)

#define XX_CONCATNAME__(a, b) a##b
#define XX_CONCATNAME_(a, b) XX_CONCATNAME__(a, b)
#define XX_CONCATNAME(a) XX_CONCATNAME_(a, __LINE__)

//#define XX_STACK_GUARD_BLOCK(x)\
//         CxxStackGuard XX_CONCATNAME(x);


#undef XX_PUBLIC

#endif




//    xxstackguard.cpp


#include "dbg/xxstackguard.h"
#include <vector>
#include <string>

#define new XX_DEBUG_NEW

class CxxStackGuardManager : public IxxStackGuardManager
{
    typedef std::vector <const char *> _Stack;

public:
    CxxStackGuardManager()
        {
        }

    virtual ~CxxStackGuardManager()
        {
            m_sReport.clear();
            m_stack.clear();
        }
    virtual void Push(const char * lpszReport)
        {
            m_stack.push_back(lpszReport);
        }

    virtual void Clear()
        {
            m_stack.clear();
            m_sReport.clear;
        }

    virtual const char * Report()
        {
            std::string space = "\r\n\t";

            m_sReport = "Stack guard:";
            for (_Stack::iterator iter = m_stack.begin(); 
                iter != m_stack.end(); ++ iter)
                m_sReport += space + std::string(*(iter));

            return m_sReport.c_str();
        }
protected:
    _Stack m_stack;
    std::string m_sReport;
};

EXTERN_C XX_EXPORT IxxStackGuardManager * xxGetStackGuardManager()
{
#ifndef _MT
    static CxxStackGuardManager stackManager;
    return &stackManager;
#else
        // Много поточный режим, пока, не реализован,
        // но его легко реализовать либо через <mep> либо через Tls
        // Эта функция вызывается в случае падения программы, поэтому 
        // скорость здесь не критична. 
        #error !!!
#endif
}


Пример:


void f1();
void f2();
void f3(int * p);

void f1()
{
    XX_STACK_GUARD;

    f2();
}


void f2()
{
    XX_STACK_GUARD;

    f3(0);
}


void f3(int * p)
{
    XX_STACK_GUARD;

    std::cout << "babah - " << *p << std::endl;
}

int main (...)
{
   try
   {
       XX_STACK_GUARD;

       f1();
   }
   catch (...)
   {
       std::cerr << xxGetStackGuardManager()->Report() << std::endl;
   }
}


У этого метода есть один недостаток: иногда в отчет не попадает функция, в которой произошел бабах (f3).
(в данном случае в дебаге отчет __должен__ быть такой — "f3 — f2 — f1 — main" а в релизе __может__
быть такой — "f2 — f1 — main").
как правило, это происходит, если функция f3 очень простая (до оптимизировались).

Но несмотря на это он в разы уменьшает время локализации и устранения ошибки (ошибок).
Re[2]: получение call stack при падении программы
От: MaximE Великобритания  
Дата: 27.12.04 12:34
Оценка: 1 (1) +1
kmn wrote:

> Здравствуйте, betauser, Вы писали:

>
> B>вот к примеру у меня упала прога.
> B>(ну допустим обратились вне адресного пространства)
> B>мне нужно получить call stack того места где это произошло.
> B>при этом это release версия приложения. (и мы не в debug'e сидим)
> B>как это реализовать?
>
> B>вариант наставить в каждой функции exception не подходит.
>
> Вот что мы в своих проектах используем.

[]

На виндозе не проще ли запользовать DbgHelp API?

http://msdn.microsoft.com/msdnmag/issues/02/03/hood/default.aspx

I've also provided a nifty class (WheatyExceptionReport) that can be easily dropped into C++-based projects to provide a detailed crash report, including the names and values of all local and global variables at the time of a program crash.


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 delta
Re[3]: получение call stack при падении программы
От: kmn Украина  
Дата: 27.12.04 13:11
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>На виндозе не проще ли запользовать DbgHelp API?


Может быть, но наш проект стремится стать кроссплатформенным.
Re[4]: получение call stack при падении программы
От: MaximE Великобритания  
Дата: 27.12.04 13:25
Оценка:
kmn wrote:

> ME>На виндозе не проще ли запользовать DbgHelp API?

>
> Может быть, но наш проект стремится стать кроссплатформенным.

Меня смутила некроссплатформенная проверка:

#if (_MSC_VER >= 1300)


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 delta
Re[5]: получение call stack при падении программы
От: kmn Украина  
Дата: 27.12.04 14:03
Оценка:
Здравствуйте, MaximE, Вы писали:


ME>Меня смутила некроссплатформенная проверка:


ME>
ME>#if (_MSC_VER >= 1300)
ME>


ME>--

ME>Maxim Yegorushkin

Я же говорю — стремится
да, а что Вас смутило?
Re: получение call stack при падении программы
От: pavel_turbin  
Дата: 27.12.04 16:07
Оценка: 1 (1)
Здравствуйте, betauser, Вы писали:

B>вот к примеру у меня упала прога.

B>(ну допустим обратились вне адресного пространства)
B>мне нужно получить call stack того места где это произошло.
B>при этом это release версия приложения. (и мы не в debug'e сидим)
B>как это реализовать?

B>вариант наставить в каждой функции exception не подходит.


я использую MiniDumpWriteDump:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/minidumpwritedump.asp

чтобы MiniDumpWriteDump использовать ставлю exception handler на App и когда падаем пишу дамп из хэндлера. Потом через WinDbg нахожу что упало. Значительно помогает генерация PDB файлов.
Re[3]: получение call stack при падении программы
От: LaFlour Австралия blog: http://spaces.live.com/laflour
Дата: 28.12.04 08:50
Оценка:
Здравствуйте, MaximE, Вы писали:


ME>На виндозе не проще ли запользовать DbgHelp API?


ME>http://msdn.microsoft.com/msdnmag/issues/02/03/hood/default.aspx

ME>

ME>I've also provided a nifty class (WheatyExceptionReport) that can be easily dropped into C++-based projects to provide a detailed crash report, including the names and values of all local and global variables at the time of a program crash.


Это все отлично, но есть ли какието тулзы для анализа полученных отчетов и просмотра в удобочитаемов виде?

Вот приходят к нам пачками эти отчеты у кого что где упало, а хотелось бы какоето средство, чтобы техсуппорт мог бы сразу видеть в чем ошибка, не листая кипу файлов.
... << RSDN@Home 1.1.4 @@subversion >>
Re[2]: получение call stack при падении программы
От: Ignoramus  
Дата: 04.01.05 17:22
Оценка:
Здравствуйте, pavel_turbin, Вы писали:

_>чтобы MiniDumpWriteDump использовать ставлю exception handler на App и когда падаем пишу дамп из хэндлера. Потом через WinDbg нахожу что упало.


_>Значительно помогает генерация PDB файлов.


Не могли бы Вы немного подробнее рассказать. Я сделал именно так, как Вы описали.

Тестеру передается релиз версия без дебаговой информации. С моей стороны у меня есть PDB-файл. Когда у тестера случается крэш, он шлет мне минидамп (DMP). Я открываю его в WinDbg.

Проблема: как сделать так, чтобы WinDbg воспринимал мой PDB файл и показывал его символы? Вообще, какая должна быть последовательность действий в WinDbg, чтобы узнать в какой из моих функций "упало"?

Заранее спасибо.
Re[2]: получение call stack при падении программы
От: Кодёнок  
Дата: 05.01.05 09:16
Оценка:
А есть ли такое решение, чтобы написать небольшой файл с содержимым стека и md5 exe-файла+указанных мною модулей (или даже адресами функций после разбора фреймов) *без* *помощи* DbgHelp.dll. А я уж имея PDB разберу этот файл, а по md5 определю версию модулей (это чтобы не связываться с версиями).
Re[3]: получение call stack при падении программы
От: pavel_turbin  
Дата: 11.01.05 11:42
Оценка: 15 (3)
I>Не могли бы Вы немного подробнее рассказать. Я сделал именно так, как Вы описали.
1. имеем DMP file and PDB

2. запускаем windbg
3. сначала окрываем dmp: menu file -->Open Crash dump, выбираем нащ дамп.
3. устанавливаем символы: menu file -->"Symbols file path". Здесь в окне вводим путь в Вашему PDB и отмечаем reload checkbox. Жмем OK.
4. в коммандной строке главного окна вводим команду
!analyze -v
она выдаст стек и прочие радости.
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************

..... сдесь будет стек. Если PDB не найден, то стек будеть корявый.


windbg имеет хорщий help. Можно начать с чтения "Analyzing a User-Mode Dump File"

Павел
Re[4]: получение call stack при падении программы
От: kondrik  
Дата: 12.07.07 12:00
Оценка:
Здравствуйте, pavel_turbin, Вы писали:


_>1. имеем DMP file and PDB


_>2. запускаем windbg

_>3. сначала окрываем dmp: menu file -->Open Crash dump, выбираем нащ дамп.
_>3. устанавливаем символы: menu file -->"Symbols file path". Здесь в окне вводим путь в Вашему PDB и отмечаем reload checkbox. Жмем OK.
_>4. в коммандной строке главного окна вводим команду
_>!analyze -v
_>она выдаст стек и прочие радости.
_>*******************************************************************************
_>* *
_>* Exception Analysis *
_>* *
_>*******************************************************************************

_>..... сдесь будет стек. Если PDB не найден, то стек будеть корявый.


Пробую делать так как здесь сказанно, но не нахожу папки с MiniDump в папке Windows. Проверял в настройках винды — указано создавать малый дамп в %SystemRoot%\Minidump. Но папки такой здесь нет. Использую Windows XP sp1.
.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.