简体   繁体   English

gdb监视点未激活

[英]gdb watchpoint not activated

Consider the code: 考虑代码:

#include <stdio.h>
#include <stdlib.h>

int update (int *arr, int size);

#define SIZE 10

int main() { // <---------------------- Breakpoint 1
  int x[SIZE];

  // Initialize array
  for (int c = 0 ; c < SIZE ; c++) {
    x[c] = c * 2;
  }

  // Do some random updates to an array
  update((int*) &x, SIZE);

  // Print the elements
  for (int c = 0 ; c < SIZE ; c++) {
    printf("%d\n", x[c]);
  }

  return EXIT_SUCCESS;
} //            <----------------------Breakpoint 2

int update (int *arr, int size) {
  for (int i = 0 ; i < size ; i++) {
    arr[i] += i;
    update(arr+i, size-1);
  }
  return 1;
}

Result of running info frame at breakpoint 1: 在断点1运行info frame结果:

Stack level 0, frame at 0x7ffc176b2610:
 rip = 0x56434b0d76b8 in main (array.c:12); saved rip = 0x7f8190fb92b1
 source language c.
 Arglist at 0x7ffc176b2600, args:
 Locals at 0x7ffc176b2600, Previous frame's sp is 0x7ffc176b2610
 Saved registers:
  rbp at 0x7ffc176b2600, rip at 0x7ffc176b2608

Result of running info frame at breakpoint 2: 在断点2运行info frame结果:

Stack level 0, frame at 0x7ffc176b2610:
 rip = 0x56434b0d771a in main (array.c:24); saved rip = 0x2d28490fd6501
 source language c.
 Arglist at 0x7ffc176b2600, args:
 Locals at 0x7ffc176b2600, Previous frame's sp is 0x7ffc176b2610
 Saved registers:
  rbp at 0x7ffc176b2600, rip at 0x7ffc176b2608

We see that main() 's saved return address rip at 0x7ffc176b2608 is mutated from 0x7f8190fb92b1 to 0x2d28490fd6501 between the two breakpoints. 我们看到, main()的返回地址rip at 0x7ffc176b2608突变从0x7f8190fb92b10x2d28490fd6501两个断点之间。

However, setting a watchpoint on the address of rip with watch * 0x7ffc176b2608 and running the executable anew does not pause execution between the breakpoints as expected. 但是,使用watch * 0x7ffc176b2608rip的地址上设置观察点并重新运行可执行文件不会按预期在中断点之间暂停执行。

How can this be? 怎么会这样?

-----------EDIT----------- - - - - - -编辑 - - - - - -

Output of disassemble /s main : disassemble /s main输出:

Dump of assembler code for function main:
array.c:
8   int main() {
   0x000056434b0d76b0 <+0>: push   rbp
   0x000056434b0d76b1 <+1>: mov    rbp,rsp
   0x000056434b0d76b4 <+4>: sub    rsp,0x30

9     int x[SIZE];
10  
11    // Initialize array
12    for (int c = 0 ; c < SIZE ; c++) {
   0x000056434b0d76b8 <+8>: mov    DWORD PTR [rbp-0x4],0x0
   0x000056434b0d76bf <+15>:    jmp    0x56434b0d76d4 <main+36>

13      x[c] = c * 2;
   0x000056434b0d76c1 <+17>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000056434b0d76c4 <+20>:    lea    edx,[rax+rax*1]
   0x000056434b0d76c7 <+23>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000056434b0d76ca <+26>:    cdqe   
   0x000056434b0d76cc <+28>:    mov    DWORD PTR [rbp+rax*4-0x30],edx

12    for (int c = 0 ; c < SIZE ; c++) {
   0x000056434b0d76d0 <+32>:    add    DWORD PTR [rbp-0x4],0x1
   0x000056434b0d76d4 <+36>:    cmp    DWORD PTR [rbp-0x4],0x9
   0x000056434b0d76d8 <+40>:    jle    0x56434b0d76c1 <main+17>

14    }
15  
16    // Do some random updates to an array
17    update((int*) &x, SIZE);
   0x000056434b0d76da <+42>:    lea    rax,[rbp-0x30]
   0x000056434b0d76de <+46>:    mov    esi,0xa
   0x000056434b0d76e3 <+51>:    mov    rdi,rax
   0x000056434b0d76e6 <+54>:    call   0x56434b0d7721 <update>

18  
19    // Print the elements
20    for (int c = 0 ; c < SIZE ; c++) {
   0x000056434b0d76eb <+59>:    mov    DWORD PTR [rbp-0x8],0x0
   0x000056434b0d76f2 <+66>:    jmp    0x56434b0d7714 <main+100>

21      printf("%d\n", x[c]);
   0x000056434b0d76f4 <+68>:    mov    eax,DWORD PTR [rbp-0x8]
   0x000056434b0d76f7 <+71>:    cdqe   
   0x000056434b0d76f9 <+73>:    mov    eax,DWORD PTR [rbp+rax*4-0x30]
   0x000056434b0d76fd <+77>:    mov    esi,eax
   0x000056434b0d76ff <+79>:    lea    rdi,[rip+0x12e]        # 0x56434b0d7834
   0x000056434b0d7706 <+86>:    mov    eax,0x0
   0x000056434b0d770b <+91>:    call   0x56434b0d7560 <printf@plt>

20    for (int c = 0 ; c < SIZE ; c++) {
   0x000056434b0d7710 <+96>:    add    DWORD PTR [rbp-0x8],0x1
   0x000056434b0d7714 <+100>:   cmp    DWORD PTR [rbp-0x8],0x9
   0x000056434b0d7718 <+104>:   jle    0x56434b0d76f4 <main+68>

22    }
23  
24    return EXIT_SUCCESS;
=> 0x000056434b0d771a <+106>:   mov    eax,0x0

25  }
   0x000056434b0d771f <+111>:   leave  
   0x000056434b0d7720 <+112>:   ret    
End of assembler dump.

Output of disassemble /s update : disassemble /s update输出:

Dump of assembler code for function update:
array.c:
27  int update (int *arr, int size) {
   0x000056434b0d7721 <+0>: push   rbp
   0x000056434b0d7722 <+1>: mov    rbp,rsp
   0x000056434b0d7725 <+4>: sub    rsp,0x20
   0x000056434b0d7729 <+8>: mov    QWORD PTR [rbp-0x18],rdi
   0x000056434b0d772d <+12>:    mov    DWORD PTR [rbp-0x1c],esi

28    for (int i = 0 ; i < size ; i++) {
   0x000056434b0d7730 <+15>:    mov    DWORD PTR [rbp-0x4],0x0
   0x000056434b0d7737 <+22>:    jmp    0x56434b0d7793 <update+114>

29      arr[i] += i;
   0x000056434b0d7739 <+24>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000056434b0d773c <+27>:    cdqe   
   0x000056434b0d773e <+29>:    lea    rdx,[rax*4+0x0]
   0x000056434b0d7746 <+37>:    mov    rax,QWORD PTR [rbp-0x18]
   0x000056434b0d774a <+41>:    add    rax,rdx
   0x000056434b0d774d <+44>:    mov    edx,DWORD PTR [rbp-0x4]
   0x000056434b0d7750 <+47>:    movsxd rdx,edx
   0x000056434b0d7753 <+50>:    lea    rcx,[rdx*4+0x0]
   0x000056434b0d775b <+58>:    mov    rdx,QWORD PTR [rbp-0x18]
   0x000056434b0d775f <+62>:    add    rdx,rcx
   0x000056434b0d7762 <+65>:    mov    ecx,DWORD PTR [rdx]
   0x000056434b0d7764 <+67>:    mov    edx,DWORD PTR [rbp-0x4]
   0x000056434b0d7767 <+70>:    add    edx,ecx
   0x000056434b0d7769 <+72>:    mov    DWORD PTR [rax],edx

30      update(arr+i, size-1);
   0x000056434b0d776b <+74>:    mov    eax,DWORD PTR [rbp-0x1c]
   0x000056434b0d776e <+77>:    lea    edx,[rax-0x1]
   0x000056434b0d7771 <+80>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000056434b0d7774 <+83>:    cdqe   
   0x000056434b0d7776 <+85>:    lea    rcx,[rax*4+0x0]
   0x000056434b0d777e <+93>:    mov    rax,QWORD PTR [rbp-0x18]
   0x000056434b0d7782 <+97>:    add    rax,rcx
   0x000056434b0d7785 <+100>:   mov    esi,edx
   0x000056434b0d7787 <+102>:   mov    rdi,rax
   0x000056434b0d778a <+105>:   call   0x56434b0d7721 <update>

28    for (int i = 0 ; i < size ; i++) {
   0x000056434b0d778f <+110>:   add    DWORD PTR [rbp-0x4],0x1
   0x000056434b0d7793 <+114>:   mov    eax,DWORD PTR [rbp-0x4]
   0x000056434b0d7796 <+117>:   cmp    eax,DWORD PTR [rbp-0x1c]
   0x000056434b0d7799 <+120>:   jl     0x56434b0d7739 <update+24>

31    }
32    return 1;
   0x000056434b0d779b <+122>:   mov    eax,0x1

33  }
   0x000056434b0d77a0 <+127>:   leave  
   0x000056434b0d77a1 <+128>:   ret    
End of assembler dump.

Contents of ~/.gdbinit ~/.gdbinit

# Security
set auto-load safe-path /

# Misc
set disassembly-flavor intel
set disable-randomization off
set pagination off
set follow-fork-mode child

# History
set history filename ~/.gdbhistory
set history save
set history expansion

disp/10i $pc

handle SIGXCPU SIG33 SIG35 SIGPWR nostop noprint

set tui enable

It is likely that this line in your .gdbinit is the source of your troubles: .gdbinit中的这一行可能是您麻烦的根源:

set disable-randomization off

By default, GDB disables address space layout randomization ( ASLR ). 默认情况下,GDB禁用地址空间布局随机化( ASLR )。 That means that the binary under GDB starts at exactly the same address, with exactly the same stack pointer every time it runs. 这意味着GDB下的二进制文件从完全相同的地址开始,每次运行时都具有完全相同的堆栈指针。 This is on by default precisely so you can set a watchpoints and breakpoints on a given address, and have it fire on each run. 默认情况下,这是精确启用的,因此您可以在给定地址上设置观察点和断点,并在每次运行时触发它。

By setting disable-randomization off, you are asking GDB to run your binary the same way it would run outside of GDB, ie with ASLR enabled. 通过disable-randomization ,您要求GDB以与GDB外部相同的方式运行二进制文件,即启用ASLR。 Now the location of stack variables (and globals for a PIE binary that you have) will change from run to run, and setting a watchpoint on a given stack address will only work randomly and rarely. 现在,堆栈变量(以及您拥有的PIE二进制文件的全局变量)的位置将随运行而变化,并且在给定堆栈地址上设置观察点将仅随机且很少起作用。

You can confirm that that is the cause by issuing info frame and run several times. 您可以通过发出info frame来确认这是原因,然后run几次。 You'll observe that the location where registers are saved changes between runs. 您会观察到寄存器的存储位置在两次运行之间发生了变化。

TL;DR: Don't put settings you don't completely understand into your .gdbinit . TL; DR:不要将您不完全了解的设置放入.gdbinit

the problem with the code is the clobbering of the stack. 代码的问题在于堆栈的混乱。

The comment by @Mark Plotnick clarifies the problem and includes a suggestion on how to fix it. @Mark Plotnick的评论澄清了该问题,并提供了有关如何解决该问题的建议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM