Как говорит ниндзя, вам нужен адрес для просмотра; В этом весь смысл наблюдения. Рассмотрим следующий пример:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node {
long value;
struct node *next;
} node;
node *build_node(int x, node *next)
{
node *n = malloc(sizeof(*n));
n->value = x;
n->next = next;
return n;
}
int main()
{
node *n = build_node(1, NULL);
n = build_node(2, n);
n = build_node(3, n);
memset(&n->next->value, 0xFF, sizeof(long) + 3); // corrupt the list
return 0;
}
Здесь я генерирую список целых чисел, затем искажаю его. Давайте посмотрим, как это выглядит в GDB:
gdb -q ./a.out
Reading symbols for shared libraries .. done
(gdb) b main
Breakpoint 1 at 0x100000e0c: file foo.c, line 20.
(gdb) r
Starting program: /tmp/a.out
Reading symbols for shared libraries +. done
Breakpoint 1, main () at foo.c:20
20 node *n = build_node(1, NULL);
(gdb) b 26
Breakpoint 2 at 0x100000e8d: file foo.c, line 26.
(gdb) c
Continuing.
Breakpoint 2, main () at foo.c:26
26 return 0;
(gdb) p *n
$1 = {
value = 3,
next = 0x100100090
}
(gdb) p *n.next
$2 = {
value = -1,
next = 0x100ffffff
}
Здесь мы ясно видим, что n->next
полностью испорчено. Предположим, что мы не знали, где это происходит, и хотели узнать об этом через точку наблюдения GDB.
Сначала нам нужно установить адрес, который был поврежден:
(gdb) print &n.next.value
$3 = (long int *) 0x100100090
(gdb) watch *$3
Hardware watchpoint 3: *$3
Здесь я просто установил точку наблюдения по адресу 0x100100090 на 8 байтов.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /private/tmp/a.out
warning: Could not set watchpoint 3
warning: Could not set watchpoint 3
Breakpoint 1, main () at foo.c:20
20 node *n = build_node(1, NULL);
Я использую довольно старую версию GDB, которая не понимает, как правильно отключать и повторно включать аппаратные точки наблюдения при перезапуске программы. Если вы используете более свежую версию, вы, скорее всего, не увидите предупреждения выше. Я могу просто снова включить точку наблюдения, когда остановлен на точке останова 1:
(gdb) enable 3
(gdb) c
Continuing.
Hardware watchpoint 3: *$3
Old value = 0
New value = 2
build_node (x=2, next=0x100100080) at foo.c:14
14 n->next = next;
Хорошо, мы достигли ожидаемой точки и ожидаемого значения. Следующая модификация испортит его, и мы хотим знать, где это происходит.
(gdb) c
Continuing.
Hardware watchpoint 3: *$3
Old value = 2
New value = 255
0x00007fff82fae450 in memset ()
(gdb) bt
#0 0x00007fff82fae450 in memset ()
#1 0x0000000100000ebe in __inline_memset_chk (__dest=0x100100090, __val=255, __len=11) at _string.h:80
#2 0x0000000100000e8d in main () at foo.c:24
Вуаля, теперь ты знаешь, откуда взялась неожиданная модификация.