Re: GDB 13.2: breakpoint at wrong line after unrelated change

Simon Marchi via Gdb <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
On 3/11/24 15:38, Paul Smith via Gdb wrote:
> On Mon, 2024-03-11 at 15:14 -0400, Simon Marchi wrote:
>>> I have noticed that if I only include the templated function
>>> definition but don't call it, then the problem doesn't happen.
>>
>> When you say that, does it mean that you just define the templated
>> function, or do you manually instantiate it?  In other words, does it
>> cause any code to be generated?
> 
> If I just define the templated function I don't see the issue.  If I
> invoke the templated function, I get the problem.
> 
> FYI I'm switching to the fmt library (if you're familiar with that)

Yes, I love it, we should use it in GDB :).

> and
> the templated function invokes it; it's something like this:
> 
>     void criticalErrorV(fmt::string_view fmt, const char *file, int line,
>                         fmt::format_args args);
> 
>     template <typename... Args>
>     void criticalError(fmt::format_string<Args...> fmt,
>                        const char* file, int line, Args &&...args)
>     {
>         criticalErrorV(fmt, file, line, fmt::make_format_args(args...));
>     }
> 
> If I never call criticalError() then it works fine (or in my previous
> implementation, which used printf-style calls with stdarg, it worked
> fine as well).

If you never call it, if never generates code, so it kinda make sense
that it doesn't change anything.

> If I have some invocation of criticalError() somewhere in the
> translation unit, I get this problem.  I haven't checked moving it
> around to see if it needs to be invoked before/after the "problem"
> method in the TU to get this behavior.
> 
>> I don't really have an idea of what's happening, but you could try
>> showing what the "disas" command shows after hitting the breakpoint
>> in both cases (the `=>` should show where you are stopped, so where
>> the breakpoint was set).
> 
> Good idea; here's what I get for the correct behavior:
> 
>    0x000000000053209c <+0>:     push   %rbp
>    0x000000000053209d <+1>:     mov    %rsp,%rbp
>    0x00000000005320a0 <+4>:     lea    -0x10(%rsp),%rsp
>    0x00000000005320a5 <+9>:     mov    %rdi,-0x8(%rbp)
>    0x00000000005320a9 <+13>:    mov    %rsi,-0x10(%rbp)
> => 0x00000000005320ad <+17>:    mov    -0x10(%rbp),%rax
>    0x00000000005320b1 <+21>:    mov    %rax,%rsi
>    0x00000000005320b4 <+24>:    lea    0x17e9a9(%rip),%rax        # 0x6b0a64
>    0x00000000005320bb <+31>:    mov    %rax,%rdi
>    0x00000000005320be <+34>:    mov    $0x0,%eax
>    0x00000000005320c3 <+39>:    call   0x52bc00 <printf@plt>
>    0x00000000005320c8 <+44>:    nop
>    0x00000000005320c9 <+45>:    mov    %rbp,%rsp
>    0x00000000005320cc <+48>:    pop    %rbp
>    0x00000000005320cd <+49>:    ret
> 
> Here's what I get for the incorrect behavior:
> 
> => 0x00000000005320ee <+0>:     push   %rbp
>    0x00000000005320ef <+1>:     mov    %rsp,%rbp
>    0x00000000005320f2 <+4>:     lea    -0x10(%rsp),%rsp
>    0x00000000005320f7 <+9>:     mov    %rdi,-0x8(%rbp)
>    0x00000000005320fb <+13>:    mov    %rsi,-0x10(%rbp)
>    0x00000000005320ff <+17>:    mov    -0x10(%rbp),%rax
>    0x0000000000532103 <+21>:    mov    %rax,%rsi
>    0x0000000000532106 <+24>:    lea    0x17e9d6(%rip),%rax        # 0x6b0ae3
>    0x000000000053210d <+31>:    mov    %rax,%rdi
>    0x0000000000532110 <+34>:    mov    $0x0,%eax
>    0x0000000000532115 <+39>:    call   0x52bc00 <printf@plt>
>    0x000000000053211a <+44>:    nop
>    0x000000000053211b <+45>:    mov    %rbp,%rsp
>    0x000000000053211e <+48>:    pop    %rbp
>    0x000000000053211f <+49>:    ret
> 
> It seems to have given up and just picked the first instruction :)
> 
> Here's the compile line args (removed extraneous stuff like warnings
> and preprocessor options):
> 
>   g++ -std=gnu++20 -ggdb3 -fPIC -march=haswell -mtune=intel \
>     -fno-omit-frame-pointer -O0 -pthread \
>     -o TestClass.o -c TestClass.cpp

Ok, so clearly GDB failed to analyze the prologue.  Which is weird
because the two functions are identical (modulo the addresses).  To get
to the bottom of this, you (or someone else) would need to debug GDB
itself.  If you want to do this, I would start at function
skip_prologue_using_sal, in symtab.c.  Off hand, I don't think we have a
debug switch to enable logging for prologue skipping.  It would be
useful to have some here, as we would be able to compare the logging
shown in both cases.

When you have DWARF debug info (which is your case), prologue skipping
is done using the DWARF line tables.  You could try to extract the line
tables for both versions of the function and see what's different.  But
that would probably only be useful if you're debugging GDB already.

Simon
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.