Bug 30352 - A source line with debug information cannot be “reached” in instruction-level stepping
Summary: A source line with debug information cannot be “reached” in instruction-level...
Status: RESOLVED NOTABUG
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: 13.1
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-04-14 05:50 UTC by Anonymous
Modified: 2023-04-16 22:01 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
Project(s) to access:
ssh public key:


Attachments
triggering source code of small.c (133 bytes, text/plain)
2023-04-14 05:50 UTC, Anonymous
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Anonymous 2023-04-14 05:50:23 UTC
Created attachment 14825 [details]
triggering source code of small.c

$ cat small.c -n
     1	volatile int v;
     2	
     3	int
     4	foo (char *p)
     5	{
     6	  char *p2 = p + 20;
     7	  v = p > p2;
     8	  return v;
     9	}
    10	
    11	int
    12	main ()
    13	{
    14	  char *p = (char *)__builtin_malloc (42);
    15	  int r = foo (p);
    16	  __builtin_free (p);
    17	
    18	  return 0;
    19	}


$ gcc -O1 -g small.c
$ gdb -q a.out
Reading symbols from a.out...
(gdb) start
Temporary breakpoint 1 at 0x401117: file small.c, line 7.
Starting program: /root/devil/batch/a.out 

Temporary breakpoint 1, main () at small.c:15
15	  int r = foo (p);
(gdb) s
foo (p=<optimized out>) at small.c:7
7	  v = p > p2;
(gdb) s
8	  return v;
(gdb) s
main () at small.c:18
18	  return 0;
(gdb)


$ gdb -q a.out
Reading symbols from a.out...
(gdb) start
Temporary breakpoint 1 at 0x401117: file small.c, line 7.
Starting program: /root/devil/batch/a.out 

Temporary breakpoint 1, main () at small.c:15
15	  int r = foo (p);
(gdb) si
foo (p=<optimized out>) at small.c:8
8	  return v;
(gdb) si
main () at small.c:18
18	  return 0;
(gdb) si
0x000000000040112c	18	  return 0;
(gdb)



/****************
we can found that line 7 is reached in source-level stepping. However, it cannot be reached at instruction-level stepping. I was wondering that this inconsistent behavior might misleading the users. 
****************/



$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/13.0.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc-git/configure --enable-languages=c,c++ --disable-multilib
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 13.0.0 20221107 (experimental) (GCC) 

$ gdb -v
GNU gdb (GDB) 13.0.50.20221107-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Comment 1 Tom de Vries 2023-04-16 06:55:13 UTC
(In reply to Yibiao Yang from comment #0)
> we can found that line 7 is reached in source-level stepping. However, it
> cannot be reached at instruction-level stepping. I was wondering that this
> inconsistent behavior might misleading the users. 

It's because of ( https://sourceware.org/gdb/onlinedocs/gdb/Inline-Functions.html#Inline-Functions ):
...
The body of an inlined function is directly included at its call site; unlike a non-inlined function, there are no instructions devoted to the call. GDB still pretends that the call site and the start of the inlined function are different instructions. Stepping to the call site shows the call site, and then stepping again shows the first line of the inlined function, even though no additional instructions are executed.

This makes source-level debugging much clearer; you can see both the context of the call and then the effect of the call. Only stepping by a single instruction using stepi or nexti does not do this; single instruction steps always show the inlined body.
...

If after reading this you still think it's misleading, you can file an enhancement PR to let users turn off this feature.

For now, resolving as not-a-bug.
Comment 2 Tom de Vries 2023-04-16 08:30:27 UTC
(In reply to Tom de Vries from comment #1)
> If after reading this you still think it's misleading, you can file an
> enhancement PR to let users turn off this feature.

Also, you can look into "set print frame-info " ( https://sourceware.org/gdb/onlinedocs/gdb/Print-Settings.html#index-set-print-frame_002dinfo ).

For instance, location-and-address makes it more clear when this behavior is happening: the line number changes but the pc stays the same.

Alternatively, you could consider using TUI, with a asm/src layout:
...
(gdb) tui new-layout src-asm src 1 asm 1 status 0 cmd 1
(gdb) layout src-asm
...

You can see both the current instruction, and the current line, so it's easy to see when you're executing an insn in main but the line is in foo.
Comment 3 Tom de Vries 2023-04-16 09:21:01 UTC
(In reply to Tom de Vries from comment #2)
> Alternatively, you could consider using TUI, with a asm/src layout:
> ...
> (gdb) tui new-layout src-asm src 1 asm 1 status 0 cmd 1
> (gdb) layout src-asm
> ...
> 
> You can see both the current instruction, and the current line, so it's easy
> to see when you're executing an insn in main but the line is in foo.

Like so:
...
┌─test.c─────────────────────────────────────────────────────────────────────┐
│  >     7   v = p > p2;                                                     │
│        8   return v;                                                       │
│        9 }                                                                 │
│       10                                                                   │
┌────────────────────────────────────────────────────────────────────────────┐
│  >0x4004a7 <main>         movl   $0x0,0x1b73(%rip)        # 0x402024 <v>   │
│   0x4004b1 <main+10>      mov    0x1b6d(%rip),%eax        # 0x402024 <v>   │
│   0x4004b7 <main+16>      mov    $0x0,%eax                                 │
└────────────────────────────────────────────────────────────────────────────┘
native process 5771 In: main                               L7    PC: 0x4004a7 
(gdb) 
...
Comment 4 Anonymous 2023-04-16 14:57:21 UTC
(In reply to Tom de Vries from comment #2)
> (In reply to Tom de Vries from comment #1)
> > If after reading this you still think it's misleading, you can file an
> > enhancement PR to let users turn off this feature.
> 
> Also, you can look into "set print frame-info " (
> https://sourceware.org/gdb/onlinedocs/gdb/Print-Settings.html#index-set-
> print-frame_002dinfo ).
> 
> For instance, location-and-address makes it more clear when this behavior is
> happening: the line number changes but the pc stays the same.
> 
> Alternatively, you could consider using TUI, with a asm/src layout:
> ...
> (gdb) tui new-layout src-asm src 1 asm 1 status 0 cmd 1
> (gdb) layout src-asm
> ...
> 
> You can see both the current instruction, and the current line, so it's easy
> to see when you're executing an insn in main but the line is in foo.

Thank you very much for the detailed explanation. Yes, I can found that the instruction is not changed when using source-level stepping for this inlined function. After reading GDB's default behavior for inlined function you mentioned, I understand why debugger has such a behavior. However, I was wondering the GCC side could do better for inlined functions by establishing a mapping between the inserted copy function body with the orginal function code when the '-g' flag is enabled. In this way, gdb can display which source code the instruction belongs to when stepping at instruction level.
Comment 5 Tom de Vries 2023-04-16 22:01:31 UTC
(In reply to Yibiao Yang from comment #4)
> Thank you very much for the detailed explanation. Yes, I can found that the
> instruction is not changed when using source-level stepping for this inlined
> function. After reading GDB's default behavior for inlined function you
> mentioned, I understand why debugger has such a behavior.

Ack.

> However, I was
> wondering the GCC side could do better for inlined functions by establishing
> a mapping between the inserted copy function body with the orginal function
> code when the '-g' flag is enabled.

Well, that information is there in the form of DW_TAG_inlined_subroutine, which is why you're seeing what you're seeing when stepping.

> In this way, gdb can display which
> source code the instruction belongs to when stepping at instruction level.

Well, AFAIU, gdb does exactly that, using the line info.