Точка останова условия на кадрах с более высоким стеком

Можно ли в отладчике MSVC++ создать точку останова в одной функции, состояние которой зависит от локальных переменных из других кадров стека? Я часто обнаруживаю, что создаю условную точку останова в одной функции, и когда эта точка останова срабатывает, я включаю другую точку останова (которая, как я ожидаю, сработает перед выходом из текущего вызова функции) и продолжаю. Это отнимает много времени и подвержено ошибкам.

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


person Sneftel    schedule 07.05.2014    source источник
comment
Вы можете сделать так, чтобы точка останова запускала макрос при попадании (щелкните ее правой кнопкой мыши в окне «Точки останова», выберите «При попадании»). Хотя сам никогда этого не пробовал. Посмотрим, сможешь ли ты извлечь из этого пользу.   -  person Igor Tandetnik    schedule 08.05.2014
comment
В VS2012 удалена поддержка макросов. Кроме того, поддержка макросов в VS2010 в основном представляет собой поле со списком; надо бы макрос каждый раз настраивать.   -  person Sneftel    schedule 14.05.2014


Ответы (1)


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

Простой пример:

#include "stdafx.h"
#include <iostream>

void foo() {
    for (int ix = 0; ix < 5; ++ix) {
        std::cout << ix << " ";                 // <=== Conditional breakpoint here
    }
}

void bar() {
    for (int jx = 0; jx < 5; ++jx) {
        std::cout << jx << ": ";                // <=== Start with a breakpoint here
        foo();
        std::cout << std::endl;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    bar();
    return 0;
}

Сначала вам нужно получить адрес переменной, для которой вы хотите установить условие. Установите точку останова на указанной строке в bar(). Когда он сработает, оцените &jx и скопируйте значение.

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

  *(int*)0x0073fbc8 == 2 && ix == 3

Где 0x0073fbc8 было значением, которое я получил в первой точке останова. Или вы можете сделать его относительным из регистра базового указателя. Установите безусловную точку останова, и когда она сработает, используйте Debug + Windows + Registers, чтобы посмотреть значение EBP. Вычтите его из значения &jx. Я использовал:

  *(int*)(ebp+0xd8) == 2 && ix == 3

Оба работали хорошо. Обратите внимание, что вам нужно отключить ASLR для отладочной сборки, чтобы иметь некоторую надежду на то, что эти адреса повторяются от одного запуска к другому. Проект + Свойства, Компоновщик, Расширенный, Рандомизированный базовый адрес = Нет.

person Hans Passant    schedule 13.05.2014
comment
Хм. Вы знаете, мне приходит в голову, что доступен регистр указателя кадра. Интересно, смогу ли я использовать его, чтобы сделать этот подход независимым от базового адреса. - person Sneftel; 14.05.2014
comment
Да, но смещение от EBP (или, что более вероятно, ESP) до переменной старшего кадра не будет зависеть от базового адреса. То есть условие может быть что-то вроде *(int*)(ESP+28) == 2. - person Sneftel; 14.05.2014
comment
Хорошо, я включу это в ответ. - person Hans Passant; 14.05.2014