стека - стандартные исключения c++




Выяснить источник исключения в C++ после его заражения? (9)

В случае, если кто-то заинтересован, сотрудник ответил на этот вопрос мне по электронной почте:

Артем писал:

В MiniDumpWriteDump () есть флаг, который может лучше справляться с дампами, которые позволят видеть полное состояние программы со всеми глобальными переменными и т. Д. Что касается стеков вызовов, я сомневаюсь, что они могут быть лучше из-за оптимизации ... если вы не включите ( возможно, некоторые) оптимизации.

Кроме того, я думаю, что отключение встроенных функций и оптимизация всей программы помогут довольно много.

На самом деле, существует много типов дампов, возможно, вы можете выбрать один достаточно маленький, но все же иметь больше информации http://msdn.microsoft.com/en-us/library/ms680519(VS.85).aspx

Эти типы не помогут в стеке вызовов, хотя они влияют только на количество переменных, которые вы сможете увидеть.

Я заметил, что некоторые из этих типов дампов не поддерживаются в dbghelp.dll версии 5.1, которые мы используем. Мы могли бы обновить его до новейшей версии 6.9, хотя я только что проверил EULA для MS Debugging Tools - самый новый dbghelp.dll по-прежнему подходит для перераспределения.

Я ищу ответ в MS VC ++.

При отладке большого приложения на C ++, которое, к сожалению, имеет очень широкое использование исключений C ++. Иногда я получаю исключение чуть позже, чем я этого хочу.

Пример в псевдокоде:

FunctionB()
{
    ...
    throw e;
    ...
}

FunctionA()
{
    ...
    FunctionB()
    ...
}

try
{
    Function A()
}
catch(e)
{
    (<--- breakpoint)
    ...
}

Я могу поймать исключение с точкой останова при отладке. Но я не могу отследить, если исключение произошло в FunctionA() или FunctionB() или какой-либо другой функции. (Предполагая широкое использование исключений и огромную версию приведенного выше примера).

Одним из решений моей проблемы является определение и сохранение стека вызовов в конструкторе исключений (т. Е. До его обнаружения). Но это потребовало бы, чтобы я получил все исключения из этого базового класса исключений. Это также потребует большого количества кода и, возможно, замедлит мою программу.

Есть ли более простой способ, который требует меньше работы? Без необходимости менять мою большую базу кода?

Есть ли лучшие решения этой проблемы на других языках?


Вот как я это делаю на C ++, используя библиотеки GCC:

#include <execinfo.h> // Backtrace
#include <cxxabi.h> // Demangling

vector<Str> backtrace(size_t numskip) {
    vector<Str> result;
    std::vector<void*> bt(100);
    bt.resize(backtrace(&(*bt.begin()), bt.size()));
    char **btsyms = backtrace_symbols(&(*bt.begin()), bt.size());
    if (btsyms) {
        for (size_t i = numskip; i < bt.size(); i++) {
            Aiss in(btsyms[i]);
            int idx = 0; Astr nt, addr, mangled;
            in >> idx >> nt >> addr >> mangled;
            if (mangled == "start") break;
            int status = 0;
            char *demangled = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);

            Str frame = (status==0) ? Str(demangled, demangled+strlen(demangled)) : 
                                      Str(mangled.begin(), mangled.end());
            result.push_back(frame);

            free(demangled);
        }
        free(btsyms);
    }
    return result;
}

Конструктор исключения может просто вызвать эту функцию и сохранить трассировку стека. Он принимает param numskip потому что мне нравится numskip конструктор исключения из моих стековых следов.


Другие языки? Ну, на Java вы вызываете e.printStackTrace (); Это не намного проще.


Есть замечательная книга, написанная Джоном Роббинсом, которая занимается многими сложными вопросами отладки. Книга называется Отладка приложений для Microsoft .NET и Microsoft Windows . Несмотря на название, книга содержит множество информации об отладке родных приложений на C ++.

В этой книге содержится длинный раздел о том, как получить стек вызовов для исключений, которые были выбраны. Если я правильно помню, некоторые его советы включают использование структурированной обработки исключений (SEH) вместо (или в дополнение) исключений C ++. Я действительно не могу рекомендовать книгу достаточно высоко.


Я использую свои собственные исключения. Вы можете справиться с ними довольно просто - также они содержат текст. Я использую формат:

throw Exception( "comms::serial::serial( )", "Something failed!" );

Также у меня есть второй формат исключения:

throw Exception( "comms::serial::serial( )", ::GetLastError( ) );

Затем он преобразуется из значения DWORD в фактическое сообщение с помощью FormatMessage. Использование формата where / what покажет вам, что произошло и в какой функции.


В собственном коде вы можете получить снимок при вызове вызова, установив обработчик Vectored Exception . VC ++ реализует исключения C ++ поверх исключений SEH, а векторный обработчик исключений получает первый снимок перед любыми обработчиками на основе фреймов. Однако будьте очень осторожны, проблемы, возникающие при обработке векторных исключений, могут быть трудно диагностировать.

Также у Майка Столла есть некоторые предупреждения об использовании его в приложении с управляемым кодом. Наконец, прочитайте статью Matt Pietrek и убедитесь, что вы понимаете SEH и векторную обработку исключений, прежде чем пытаться это сделать. (Ничто не чувствует себя так плохо, как отслеживание критической проблемы, чтобы код, добавленный в подсказку, устранял критические проблемы.)


Я считаю, что MSDev позволяет устанавливать точки останова при вызове исключения.

Альтернативно поместите точку останова на конструктор вашего объекта исключения.


Если вы отлаживаетесь из среды IDE, перейдите в раздел «Отладка-> Исключения», нажмите «Бросить» для исключений на C ++.


Невозможно узнать источник исключения после его захвата, если вы не включите эту информацию, когда она будет выбрана. К тому времени, когда вы поймаете исключение, стек уже размотан, и нет возможности восстановить предыдущее состояние стека.

Ваше предложение включить трассировку стека в конструкторе - ваш лучший выбор. Да, это стоит времени во время строительства, но вы, вероятно, не должны бросать исключения, достаточно часто, что это вызывает беспокойство. Заполнение всех ваших исключений, наследуемых с новой базы, также может быть больше, чем вам нужно. Вы могли бы просто иметь соответствующие исключения наследовать (спасибо, множественное наследование) и иметь отдельный улов для них.

Вы можете использовать функцию StackTrace64 для построения трассировки (я считаю, что есть и другие способы). Просмотрите эту статью, например, код.





visual-c++