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