Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

An address belongs to different source code lines when debugging at source-level and instruction-level #47437

Open Quuxplusone opened 3 years ago

Quuxplusone commented 3 years ago
Bugzilla Link PR48468
Status NEW
Importance P normal
Reported by Yibiao Yang (yangyibiao@nju.edu.cn)
Reported on 2020-12-10 00:17:36 -0800
Last modified on 2020-12-10 17:51:05 -0800
Version unspecified
Hardware PC Linux
CC dblaikie@gmail.com, jdevlieghere@apple.com, llvm-bugs@lists.llvm.org
Fixed by commit(s)
Attachments a.out (9352 bytes, application/x-executable)
Blocks
Blocked by
See also
Created attachment 24260
binary

$ clang -v
Ubuntu clang version 12.0.0-++20201202063839+f0193623297-
1~exp1~20201202174527.2077
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Candidate multilib: .;@m64
Selected multilib: .;@m64

$ lldb -v
lldb version 12.0.0

$ cat small.c
int a[2];

int foo(int n)
{
  switch(n) {
    case 0:
      for(n = 7, a[0]++; 0;) {
    case 2:
        a[1] = a[0] + 1;
      }
  }
  return n;
}

void main()
{
  foo(0);
  foo(2);
}

$ clang -O2 -g small.c

$ lldb a.out
(lldb) b main
Breakpoint 1: where = a.out`main [inlined] foo at small.c:17, address =
0x00000000004004d0
(lldb) r
    frame #0: 0x00000000004004d0 a.out`main [inlined] foo(n=7) at small.c:7:22
-> 7          for(n = 7, a[0]++; 0;) {
(lldb) s
    frame #0: 0x00000000004004df a.out`main at small.c:18
-> 18     foo(2);
(lldb) s
    frame #0: 0x00000000004004df a.out`main [inlined] foo(n=2) at small.c:9:21
-> 9            a[1] = a[0] + 1;
(lldb)

###############################################
when step line by line, 0x00000000004004df belongs to Line 18 and Line 9.
However, when step instruction by instruction, 0x00000000004004df only belongs
to Line 18 as follow.
###############################################

$ lldb a.out
(lldb) b main
Breakpoint 1: where = a.out`main [inlined] foo at small.c:17, address =
0x00000000004004d0
(lldb) r
    frame #0: 0x00000000004004d0 a.out`main [inlined] foo(n=7) at small.c:7:22
-> 7          for(n = 7, a[0]++; 0;) {
(lldb) si
    frame #0: 0x00000000004004d6 a.out`main [inlined] foo(n=7) at small.c:7:22
-> 7          for(n = 7, a[0]++; 0;) {
(lldb) si
    frame #0: 0x00000000004004d9 a.out`main [inlined] foo(n=7) at small.c:7:22
-> 7          for(n = 7, a[0]++; 0;) {
(lldb) si
    frame #0: 0x00000000004004df a.out`main at small.c:18
-> 18     foo(2);
(lldb) si
    frame #0: 0x00000000004004e2 a.out`main [inlined] foo(n=2) at small.c:9:14
-> 9            a[1] = a[0] + 1;
(lldb)
Quuxplusone commented 3 years ago

Attached a.out (9352 bytes, application/x-executable): binary

Quuxplusone commented 3 years ago
This is probably duplicate with https://bugs.llvm.org/show_bug.cgi?id=48467 and
I suspect both are intentional behavior.

Here's a simple example:

1: void f1() { }
2: __attribute__((always_inline)) void f2() { f1(); }
3: int main() {
4:   f1();
5:   f2();
6: }

(the first f1() call isn't strictly necessary, but makes things a bit more
obvious/clearer I think)

If you step through main - you go something like 4, 1, 5, 2, 1, 2, 6. the {5,
2} portion are at the same instruction. This is lldb synthesizing what it would
be like to be at the call, but before executing the call, then stepping into
the function call - the experience you would get with a real function call,
but. with an inlined function call those two locations exist at the same
instruction - so lldb has synthesized the experience of them being distinct
locations.

But 'si' does what it says: steps to the next instruction - so in favoring the
literal definition of the next instruction, no frame is synthesized.
Quuxplusone commented 3 years ago

(In reply to David Blaikie from comment #1)

This is probably duplicate with https://bugs.llvm.org/show_bug.cgi?id=48467 and I suspect both are intentional behavior.

Here's a simple example:

1: void f1() { } 2: attribute((always_inline)) void f2() { f1(); } 3: int main() { 4: f1(); 5: f2(); 6: }

(the first f1() call isn't strictly necessary, but makes things a bit more obvious/clearer I think)

If you step through main - you go something like 4, 1, 5, 2, 1, 2, 6. the {5, 2} portion are at the same instruction. This is lldb synthesizing what it would be like to be at the call, but before executing the call, then stepping into the function call - the experience you would get with a real function call, but. with an inlined function call those two locations exist at the same instruction - so lldb has synthesized the experience of them being distinct locations.

But 'si' does what it says: steps to the next instruction - so in favoring the literal definition of the next instruction, no frame is synthesized.

Thanks. I agree and understand that this is indeed an inlined function call. The current form will mislead developers into thinking that stepping is not moving forward. Thus, I was wondering whether it is possible for lldb to behave as step a new instruction like si when stepping a new line?

Quuxplusone commented 3 years ago

(In reply to Yibiao Yang from comment #2)

(In reply to David Blaikie from comment #1)

This is probably duplicate with https://bugs.llvm.org/show_bug.cgi?id=48467 and I suspect both are intentional behavior.

Here's a simple example:

1: void f1() { } 2: attribute((always_inline)) void f2() { f1(); } 3: int main() { 4: f1(); 5: f2(); 6: }

(the first f1() call isn't strictly necessary, but makes things a bit more obvious/clearer I think)

If you step through main - you go something like 4, 1, 5, 2, 1, 2, 6. the {5, 2} portion are at the same instruction. This is lldb synthesizing what it would be like to be at the call, but before executing the call, then stepping into the function call - the experience you would get with a real function call, but. with an inlined function call those two locations exist at the same instruction - so lldb has synthesized the experience of them being distinct locations.

But 'si' does what it says: steps to the next instruction - so in favoring the literal definition of the next instruction, no frame is synthesized.

Thanks. I agree and understand that this is indeed an inlined function call. The current form will mislead developers into thinking that stepping is not moving forward. Thus, I was wondering whether it is possible for lldb to behave as step a new instruction like si when stepping a new line?

Can't say I know - perhaps someone from lldb will chime in. My guess would be the current behavior's the best default, but perhaps there's a flag/mode/option/something to opt out of this behavior.