2010-08-12 3 views
16

An earlier question объяснил, что размер объекта, просматриваемого на x86, ограничен регистрами отладки. Как и ожидалось, я могу «наблюдать» двойную переменную. Но я не могу смотреть двойной DataMember, например,Настройка точки наблюдения аппаратного обеспечения GDB/как установить контрольную точку программного обеспечения

watch pObject->dPrice 

производит

Hardware watchpoint 1: pObject->dPrice 

Но при попытке продолжить выполнение, он говорит

Не удалось вставить аппаратные точки останова: Возможно, вы запросили слишком много аппаратных контрольных точек/точек наблюдения.

, хотя это только точка останова/точка наблюдения.

Мне любопытно, почему это так, но что еще более важно, есть ли способ вокруг него? Согласно документации GDB, он может использовать точки наблюдения программного обеспечения, если он не может использовать аппаратное обеспечение. В этом случае он не пытается использовать контрольную точку программного обеспечения - есть ли способ заставить это сделать это?

+0

Вы можете напечатать адрес этой переменной-члена? Мое подозрение было бы оптимизировано в регистр. Если это не так, правильно ли оно выровнено? –

ответ

15

Да, вы можете:

набор может потребительной HW-точки наблюдения 0

От 5.1.2 Setting Watchpoints:

Вы можете заставить GDB использовать только программные точки наблюдения с set can-use-hw-watchpoints 0. Когда эта переменная установлена ​​на ноль, GDB никогда не будет пытаться использовать аппаратные точки наблюдения, даже если базовая система их поддерживает. (Обратите внимание, что аппаратной помощью точку наблюдения, которые были установлены перед установкой можно-использовать-HW-точку наблюдение до нуля будет по-прежнему использовать аппаратный механизм, наблюдая значение выражений.)

set can-use-hw-watchpoints

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

show can-use-hw-watchpoints

        Показать текущий режим использования аппаратных точек наблюдения.

+0

Спасибо! Я просто читал эту секцию, но, очевидно, я не очень внимательно читал. –

+1

Это работает, но это немного медленнее, чем аппаратное. В моем случае около 1/5000 скорости. – wallyk

7

Я не уверен на 100%, но я понимаю, что когда вы смотрите pObject->dPrice, GDB пытается посмотреть все, что может изменить наблюдаемое значение.

Использование контрольных точек программного обеспечения после каждого шага GDB проверяет, изменилось ли выражение. Используя аппаратные точки наблюдения, GDB должен установить точку наблюдения для dprice, как вы ожидаете, но также и для pObject.

Теперь вы отметили вопрос «x86». На x86 вы можете установить точки останова для четырех байтов. Двойной - восемь байтов. Если вы хотите посмотреть двойник, я бы догадался, что GDB потребует двух аппаратных точек наблюдения. Вам нужна дополнительная точка наблюдения для pObject.Я предполагаю, что GDB пытается посмотреть все из pObject, что восходит к проблеме в вопросе, который вы задали в вопросе.

Когда я хочу сделать что-то подобное, если я уверен, что указатель pObject не изменится, я обычно делаю:

p &pObject->dprice 

Скажем GDB говорит адрес (double *) 0xabcdef10, теперь я:

watch (double *) *0xabcdef10 

и смотреть только то, что я хочу.

Примечание: У меня нет открытого GDB передо мной, поэтому у меня может быть точный синтаксис для команды watch (относительно размещения *), поэтому сначала проверьте его.

+2

Было бы неплохо, если бы gdb предложил ярлык для «смотреть только конечную цель» –

+3

@CraigRinger: [Это так.] (Http://stackoverflow.com/questions/25938830/gdb-how-to-force-a -watchpoint-to-not-be-deleted-after-a-function-return) 'watch -location pObject-> dprice' – Alcaro

+0

@Alcaro: 1. поддерживается ли это в любой версии gdb? 2. Это достаточно хороший ответ, что он должен быть в автономном ответе, а не как комментарий к моему ответу. –

2

Короткий ответ: используйте watch -location pObject->dPrice, или короткую форму watch -l.

Длинный ответ: Quoting the GDB manual:

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

GDB буквально наблюдает за самим выражением, а не за любой адрес, на который он указывает. В этом случае это означает, что точка останова будет удалена, если pObject сам будет изменен, чтобы указать на новый dPrice; есть не только точка наблюдения за pObject->dPrice, но и одна для pObject. Это может быть больше, чем доступно.

Более подробный пример:

// Set a watchpoint on '*p' before running 
#include <stdio.h> 

int a = 0; 
int b = 0; 
int c = 0; 
int* p = &a; 

int main() 
{ 
    puts("Hi"); // Dummy lines to make the results clearer, watchpoints stop at the line after the change 
    *p = 1; // Breaks: *p was changed from 0 to 1 
    puts("Hi"); 
    a = 2; // Breaks: a is *p, which changed from 1 to 2 
    puts("Hi"); 
    p = &b; // Breaks: p is now b, changing *p from 2 to 0 
    puts("Hi"); 
    p = &c; // Doesn't break: while p changed, *p is still 0 
    puts("Hi"); 
    p = NULL; // Breaks: *p is now unreadable 
    puts("Hi"); 
    return 0; 
} 

В теории, это полезная функция; вы можете наблюдать сложное выражение, ломая, как только оно ложно, что-то вроде постоянно проверенного утверждения. Например, вы можете watch a==b в вышеуказанной программе.

На практике это неожиданно, часто вызывает эту проблему, и обычно это не то, что вы хотите.

Чтобы посмотреть только адрес цели, используйте watch -location pObject->dPrice. (Это доступно в GDB 7.3, выпущенном в июле 2011 г., если вы используете что-то более старое, используйте print &pObject->dPrice и watch *(double*)0x12345678 или любой адрес, который он печатает.)

+0

Пересекая этот ответ на [этот вопрос] (http://stackoverflow.com/questions/3206332/gdb-stops-with-too-many-watchpoints-when-there-is-only-one), он отвечает на оба , – Alcaro

Смежные вопросы