Gdb проблема установки оборудования watchpoint/как установить контрольную точку программного обеспечения
Более ранний вопрос объяснил, что на x86 размер наблюдаемых объектов ограничен регистрами отладки. здесь. Как и ожидалось, я могу "смотреть" двойную переменную. Но я не могу наблюдать за двойным сообщением, например
watch pObject->dPrice
производит
Hardware watchpoint 1: pObject->dPrice
Но когда вы пытаетесь продолжить выполнение, он говорит
Could not insert hardware breakpoints:
You may have requested too many hardware breakpoints/watchpoints.
хотя это единственная точка останова/точки наблюдения.
Мне любопытно, почему это так, но что еще более важно, есть ли способ обойти это? Согласно документам gdb, он может использовать точки наблюдения программного обеспечения, если он не может использовать аппаратное обеспечение. В этом случае он не пытается использовать контрольную точку программного обеспечения - есть ли способ заставить его сделать это?
Ответы
Ответ 1
Да, вы можете:
set can-use-hw-watchpoints 0
От 5.1.2 Настройка точек наблюдения:
Вы можете заставить gdb использовать только контрольные точки программного обеспечения с помощью команды set-use-hw-watchpoints 0. Если эта переменная установлена на ноль, gdb никогда не будет пытаться использовать аппаратные точки наблюдения, даже если базовая система их поддерживает. (Обратите внимание, что сторожевые точки с аппаратным обеспечением, которые были установлены перед установкой can-use-hw-watchpoints в ноль, по-прежнему будут использовать аппаратный механизм просмотра значений выражения.)
set can-use-hw-watchpoints
Установите, следует ли использовать точки наблюдения оборудования.
show can-use-hw-watchpoints
Показать текущий режим использования аппаратных сторожевых точек.
Ответ 2
Я не уверен на 100%, но я понимаю, что когда вы смотрите pObject->dPrice
, gdb пытается посмотреть все, что может изменить наблюдаемое значение.
Используя точки наблюдения программного обеспечения, после каждого шага gdb проверяет, изменилось ли выражение. Используя аппаратные точки наблюдения, gdb должен установить точку наблюдения для dprice
, как вы ожидаете, но также и для pObject
.
Теперь вы отметили вопрос "x86". На x86 вы можете установить точки останова для 4 байтов. Двойной - 8 байтов. Если вы хотите посмотреть двойник, я бы предположил, что для gdb понадобятся две аппаратные точки наблюдения. Вам нужна дополнительная точка наблюдения для pObject
. Я предполагаю, что gdb пытается просмотреть все pObject
, что восходит к проблеме в вопросе, который вы задали в вопросе.
Когда я хочу сделать что-то подобное, если я уверен, что указатель pObject
не изменится, я обычно делаю:
p &pObject->dprice
Скажем, gdb говорит, что адрес (double *) 0xabcdef10
, теперь я делаю:
watch (double *) *0xabcdef10
и следите за тем, что я хочу.
Примечание. У меня нет gdb открытым передо мной, поэтому я могу иметь точный синтаксис для команды watch
(относительно размещения *
), поэтому сначала проверьте его.
Ответ 3
Краткий ответ: используйте watch -location pObject->dPrice
или короткую форму watch -l
.
Длинный ответ: Цитата руководства GDB:
Просмотр сложных выражений, которые ссылаются на многие переменные, также может исчерпывать ресурсы, доступные для сторожевых точек с аппаратным обеспечением. Это потому, что 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
, или какой бы адрес он не печатал.)