最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Why isn't GDB breaking in this instruction? - Stack Overflow

programmeradmin4浏览0评论

In C, BUFFER_SIZE is a macro, this should be a compile-time memory allocation, and gdb does not break and skips the line.

#define BUFFER_SIZE 50
int main(){
  const int sz = BUFFER_SIZE;
  char buffer[BUFFER_SIZE]; // does not break when a breakpoint is specified here
}

This is a run-time allocation, gdb does break.

#define BUFFER_SIZE 50
int main(){
  const int sz = BUFFER_SIZE;
  char buffer[sz]; // it does break here
}

I think it's because compile-time evaluated instructions cannot be debugged because gdb debugs at runtime, is that correct or is there another explanation ?

In C, BUFFER_SIZE is a macro, this should be a compile-time memory allocation, and gdb does not break and skips the line.

#define BUFFER_SIZE 50
int main(){
  const int sz = BUFFER_SIZE;
  char buffer[BUFFER_SIZE]; // does not break when a breakpoint is specified here
}

This is a run-time allocation, gdb does break.

#define BUFFER_SIZE 50
int main(){
  const int sz = BUFFER_SIZE;
  char buffer[sz]; // it does break here
}

I think it's because compile-time evaluated instructions cannot be debugged because gdb debugs at runtime, is that correct or is there another explanation ?

Share Improve this question asked Mar 17 at 4:36 maths sosomaths soso 7313 bronze badges 6
  • 3 Yes, that's correct. The VLA declaration has to evaluate the size expression at run time, so you can break while it's doing that. Fixed-size arrays declarations don't have to do anything at run time. – Barmar Commented Mar 17 at 4:52
  • @3CxEZiVlQ, could you elaborate more on "observable effect" ? I can break still break in const int sz = BUFFER_SIZE; – maths soso Commented Mar 17 at 4:56
  • The fixed-size array declaration is simply included in the amount of stack space allocated for the function. – Barmar Commented Mar 17 at 5:06
  • 1 If you add an initialization to the array, that may make it executable as well. char buffer[BUFFER_SIZE] = ""; – Barmar Commented Mar 17 at 5:07
  • How do you build the program? Did you try different optimizations like -O0 and -O3? – the busybee Commented Mar 17 at 6:40
 |  Show 1 more comment

1 Answer 1

Reset to default 1

TL;DR

You can set a breakpoint only on lines that have machine instructions.

On what else could a debugger break? The same is true for single stepping.

The array definition as a local variable needs only instructions when it is a VLA, which is constructed at run-time.


The following experiments are done with MinGW for a 64 bit Windows 10 machine version 13.2.0 that I have at hand.

I compiled with the options -Wall -pedantic -g. Of course, the compiler gives me warnings because of the unused variables.

The assembly listings were generated with objdump -dS from the executables.

Compiled as C without optimization

Without optimization (-O0), as you did, the compiler generates different code.

In the first program, you have a compile-time constant for the array size. Therefore, the compiler includes the array directly in the stack space allocated for the local variables. Consequently, there is no instruction for the defining line.

0000000140001450 <main>:
#define BUFFER_SIZE 50
int main(){
   140001450:   55                      push   %rbp
   140001451:   48 89 e5                mov    %rsp,%rbp
   140001454:   48 83 ec 60             sub    $0x60,%rsp
   140001458:   e8 c3 00 00 00          call   140001520 <__main>
  const int sz = BUFFER_SIZE;
   14000145d:   c7 45 fc 32 00 00 00    movl   $0x32,-0x4(%rbp)
   140001464:   b8 00 00 00 00          mov    $0x0,%eax
  char buffer[BUFFER_SIZE]; // does not break when a breakpoint is specified here
}
   140001469:   48 83 c4 60             add    $0x60,%rsp
   14000146d:   5d                      pop    %rbp
   14000146e:   c3                      ret

In the second program, the compiler see a VLA because of the variable. It generates instructions for the allocation, so you can set a breakpoint. (Side note: By default, the compiler checks that the stack has room for the array.)

0000000140001450 <main>:
#define BUFFER_SIZE 50
int main(){
   140001450:   55                      push   %rbp
   140001451:   48 89 e5                mov    %rsp,%rbp
   140001454:   48 83 ec 40             sub    $0x40,%rsp
   140001458:   e8 03 01 00 00          call   140001560 <__main>
   14000145d:   48 89 e0                mov    %rsp,%rax
   140001460:   48 89 c2                mov    %rax,%rdx
  const int sz = BUFFER_SIZE;
   140001463:   c7 45 fc 32 00 00 00    movl   $0x32,-0x4(%rbp)
  char buffer[sz]; // it does break here
   14000146a:   8b 45 fc                mov    -0x4(%rbp),%eax
   14000146d:   48 98                   cltq
   14000146f:   48 83 e8 01             sub    $0x1,%rax
   140001473:   48 89 45 f0             mov    %rax,-0x10(%rbp)
   140001477:   8b 45 fc                mov    -0x4(%rbp),%eax
   14000147a:   48 98                   cltq
   14000147c:   48 83 c0 0f             add    $0xf,%rax
   140001480:   48 c1 e8 04             shr    $0x4,%rax
   140001484:   48 c1 e0 04             shl    $0x4,%rax
   140001488:   e8 a3 10 00 00          call   140002530 <___chkstk_ms>
   14000148d:   48 29 c4                sub    %rax,%rsp
   140001490:   48 8d 44 24 20          lea    0x20(%rsp),%rax
   140001495:   48 83 c0 00             add    $0x0,%rax
   140001499:   48 89 45 e8             mov    %rax,-0x18(%rbp)
   14000149d:   48 89 d4                mov    %rdx,%rsp
   1400014a0:   b8 00 00 00 00          mov    $0x0,%eax
}
   1400014a5:   48 89 ec                mov    %rbp,%rsp
   1400014a8:   5d                      pop    %rbp
   1400014a9:   c3                      ret

Compiled as C++ without optimization

When compiled as C++, the constant variable sz of the second program is semantically a compile-time constant, so there is no difference between both executables.

In both cases no breakpoint can be set.

0000000140001450 <main>:
#define BUFFER_SIZE 50
int main(){
   140001450:   55                      push   %rbp
   140001451:   48 89 e5                mov    %rsp,%rbp
   140001454:   48 83 ec 60             sub    $0x60,%rsp
   140001458:   e8 c3 00 00 00          call   140001520 <__main>
  const int sz = BUFFER_SIZE;
   14000145d:   c7 45 fc 32 00 00 00    movl   $0x32,-0x4(%rbp)
  char buffer[BUFFER_SIZE]; // does not break when a breakpoint is specified here
}
   140001464:   b8 00 00 00 00          mov    $0x0,%eax
   140001469:   48 83 c4 60             add    $0x60,%rsp
   14000146d:   5d                      pop    %rbp
   14000146e:   c3                      ret
0000000140001450 <main>:
#define BUFFER_SIZE 50
int main(){
   140001450:   55                      push   %rbp
   140001451:   48 89 e5                mov    %rsp,%rbp
   140001454:   48 83 ec 60             sub    $0x60,%rsp
   140001458:   e8 c3 00 00 00          call   140001520 <__main>
  const int sz = BUFFER_SIZE;
   14000145d:   c7 45 fc 32 00 00 00    movl   $0x32,-0x4(%rbp)
  char buffer[sz]; // it does break here
}
   140001464:   b8 00 00 00 00          mov    $0x0,%eax
   140001469:   48 83 c4 60             add    $0x60,%rsp
   14000146d:   5d                      pop    %rbp
   14000146e:   c3                      ret

Compiled as C with optimization

Finally I compiled both programs with -O3, which produced identical machine code. The compiler found that the variables are unused and removed them. Consequently, you cannot set a breakpoint.

0000000140002920 <main>:
#define BUFFER_SIZE 50
int main(){
   140002920:   48 83 ec 28             sub    $0x28,%rsp
   140002924:   e8 d7 eb ff ff          call   140001500 <__main>
  const int sz = BUFFER_SIZE;
  char buffer[BUFFER_SIZE]; // does not break when a breakpoint is specified here
}
   140002929:   31 c0                   xor    %eax,%eax
   14000292b:   48 83 c4 28             add    $0x28,%rsp
   14000292f:   c3                      ret
0000000140002920 <main>:
#define BUFFER_SIZE 50
int main(){
   140002920:   48 83 ec 28             sub    $0x28,%rsp
   140002924:   e8 d7 eb ff ff          call   140001500 <__main>
  const int sz = BUFFER_SIZE;
  char buffer[BUFFER_SIZE]; // does not break when a breakpoint is specified here
}
   140002929:   31 c0                   xor    %eax,%eax
   14000292b:   48 83 c4 28             add    $0x28,%rsp
   14000292f:   c3                      ret
发布评论

评论列表(0)

  1. 暂无评论