On Tue, Jan 19, 2021 at 10:17 AM Jim Ingham <jing...@apple.com> wrote: > > > > > On Jan 17, 2021, at 10:47 AM, David Blaikie <dblai...@gmail.com> wrote: > > > > On Fri, Jan 15, 2021 at 6:22 PM Jim Ingham <jing...@apple.com> wrote: > >> > >> If you set a breakpoint on source lines with no line table entries, lldb > >> slides the actual match forward to the nearest line table entry to the > >> given line number. That's necessary for instance because if you lay out > >> your function definitions over multiple lines they won't all get line > >> table entries, but we don't want people to have to guess which of them > >> was... Same is true of more complicated compound statements. > > > > Ah, sure - gdb seems to do that too, totally makes sense - as you say, > > it'd be pretty hard to know exactly which tokens end up with > > corresponding entries in the line table and which don't (especially > > under optimizations and complex compound statements). > > Yeah, I think you either have to have this heuristic, or have a debugger that > can display "valid breakpoint locations". The old Metrowerks debugger used > to do it that way. They only put up breakpoint affordances in the UI for the > lines that had line table entries and there was no free-form way to set > breakpoints, so you couldn't do an ambiguous thing. But I don't think we > have that option in lldb.
Could be nice to have in source printing on the command line and could be done more fully in IDE integrations like XCode - but yeah, still would want all this sliding stuff for raw command line usage even if we had the rest. > >> So people like that, but they really hate it when they have: > >> > >> > >> #ifdef SOMETHING_NOT_DEFINED > >> > >> int foo() { > >> > >> } > >> > >> #else > >> int bar() { > >> > >> } > >> #end > >> > >> but with lots more junk so you can't see the ifdef's and then they set a > >> breakpoint in the "int foo" part and the breakpoint gets moved to bar > >> instead and then doesn't get hit. > > > > Ah, indeed - that is a curious case that could be surprising to a > > user. Thanks for explaining it - though it seems gdb doesn't special > > case this & does produce the not-quite-what-the-user-intended > > behavior. > > > >> You might try to argue that they should have checked where the breakpoint > >> actually landed before coming into your office to yell at you, but it's > >> likely to leave you with fewer friends... > > > > FWIW: I don't have coworkers or friends come into my office to yell at > > me about anything like this, and I don't really think anyone should - > > that's not appropriate behavior for a workplace. > > > > Having a nuanced discussion about the tradeoff of features - sure. > > Yeah, IME people get cheesed off at debuggers in ways they don't with > compilers. I have some theories, but more of the after work quality than the > public mailing list quality. > > >> So I was trying to detect this case and not move the breakpoint if sliding > >> it crossed over the function start boundary. That way you'd see that the > >> breakpoint didn't work, and go figure out why. > > > > Neat idea! > > > >> The thinko in the original version was that we were still doing this when > >> we DIDN'T have to slide the breakpoint, when we got an exact match in the > >> line table. In that case, we shouldn't try to second guess the line table > >> at all. That's the patch in this fix. > > > > Might this still leave some confusing behavior. Now it'll slide > > forward into a function, but it won't slide forward into an > > initializer? (so now the user has to know exactly which lines of the > > initializer are attributed to the line table, making that somewhat > > difficult to use?) > > > Yes I knew this was a tradeoff of the implementation. If I did a more in > depth search in order to slide this over to function initializer, it would > IMO add way more complexity to an already overly fiddly part of the debugger, > and the trade-off didn't seem worth it. Most initializers have a fairly > simple structure, as opposed say to the before the body part of a function > definition (that's got to have a name, but I don't know it off the top of my > head.) So I think the payoff would be a lot less in this area. I asked > around here and the folks I polled agreed that it wasn't worth the complexity. > > > > > Testing some things out: > > > > $ cat break.cpp > > __attribute__((optnone)) int f1() { return 1; } > > struct t1 { > > int // 3 > > i // 4 > > = // 5 > > f1 // 6 > > (); > > t1() { > > } > > }; > > > > t1 v1; > > int main() { > > } > > > > The line table: > > > > Address Line Column File ISA Discriminator Flags > > ------------------ ------ ------ ------ --- ------------- ------------- > > 0x0000000000401140 1 0 1 0 0 is_stmt > > 0x0000000000401144 1 37 1 0 0 is_stmt > > prologue_end > > 0x0000000000401150 13 0 1 0 0 is_stmt > > 0x0000000000401154 14 1 1 0 0 is_stmt > > prologue_end > > 0x0000000000401158 14 1 1 0 0 is_stmt > > end_sequence > > 0x0000000000401020 0 0 1 0 0 is_stmt > > 0x0000000000401024 12 4 1 0 0 is_stmt > > prologue_end > > 0x0000000000401040 0 0 1 0 0 is_stmt > > 0x000000000040104b 0 0 1 0 0 is_stmt > > end_sequence > > 0x0000000000401160 8 0 1 0 0 is_stmt > > 0x0000000000401174 6 7 1 0 0 is_stmt > > prologue_end > > 0x000000000040117f 4 7 1 0 0 is_stmt > > 0x0000000000401181 9 3 1 0 0 is_stmt > > 0x0000000000401187 9 3 1 0 0 is_stmt > > end_sequence > > > > Has entries for line 4 and 6 from the initializer (and 8 and 9 from > > the ctor), but gdb doesn't seem to want to break on any of them. So > > I'm not sure what gdb's doing, but it seems pretty unhelpful > > (apparently gdb breaks in to the ctor too late to even let you step > > into the initializers... guess that's because the initializers are > > called in the prologue according to the debug info): > > (gdb) b 1 > > Breakpoint 1 at 0x401144: file break.cpp, line 1. > > (gdb) b 2 > > Breakpoint 2 at 0x401181: file break.cpp, line 9. > > (gdb) b 3 > > Note: breakpoint 2 also set at pc 0x401181. > > Breakpoint 3 at 0x401181: file break.cpp, line 9. > > (gdb) b 4 > > Note: breakpoints 2 and 3 also set at pc 0x401181. > > Breakpoint 4 at 0x401181: file break.cpp, line 9. > > (gdb) b 5 > > Note: breakpoints 2, 3 and 4 also set at pc 0x401181. > > Breakpoint 5 at 0x401181: file break.cpp, line 9. > > (gdb) b 6 > > Note: breakpoints 2, 3, 4 and 5 also set at pc 0x401181. > > Breakpoint 6 at 0x401181: file break.cpp, line 9. > > (gdb) b 7 > > Note: breakpoints 2, 3, 4, 5 and 6 also set at pc 0x401181. > > Breakpoint 7 at 0x401181: file break.cpp, line 9. > > (gdb) b 8 > > Note: breakpoints 2, 3, 4, 5, 6 and 7 also set at pc 0x401181. > > Breakpoint 8 at 0x401181: file break.cpp, line 9. > > (gdb) b 9 > > Note: breakpoints 2, 3, 4, 5, 6, 7 and 8 also set at pc 0x401181. > > Breakpoint 9 at 0x401181: file break.cpp, line 9. > > > > lldb does already seem to let me break on the initializer without this > > patch - so any idea what part of this already works compared to what's > > being fixed here? (though lldb breaks on line 6 even when I asked to > > break on line 7 or 8, but it doesn't break on 6 when I ask to break on > > 6... ) > > > Yes. This is because the line table entry for the "first line" of a function > is also imprecise. For instance, if you do: > > int > foo() > { > > } > > the "int" line in the function definition pretty much never gets a line table > entry, yet that's a perfectly reasonable place to set a breakpoint on the > function. So the "am I sliding across function definitions" check has a > little slop in the comparison. Just put a handful of blank lines between the > "();" of the struct initialization and the definition of the constructor, and > then the breakpoint won't take. Ah, right right - I was still a bit confused by why the line was showing as line 6, but I get it - it's because that's where the first instruction for function is. Hmm, actually that doesn't quite make sense to me still - if I set a breakpoint at line 9, why wouldn't I get a breakpoint on that line? I guess maybe lldb detects that that is the line where a function starts according to the DW_AT_decl_line in the DW_TAG_subprogram, and instead of breaking on line 9 per the line table, it breaks on the start of the function which is line 6? Though when the program... huh, it does stop at 6, even though I said break 9 (well, I said break 13 in my new example where I've added the suggested handful of blank lines) Seems a bit surprising/not something I can readily explain: $ cat -n test.cpp 1 __attribute__((optnone)) int f1() { return 1; } 2 struct t1 { 3 int // 3 4 i // 4 5 = // 5 6 f1 // 6 7 (); 8 9 10 11 12 13 t1() {} 14 }; 15 t1 v1; 16 int main() {} blaikie@blaikie-linux2:~/dev/scratch$ lldb ./a.out (lldb) target create "./a.out" Current executable set to '/usr/local/google/home/blaikie/dev/scratch/a.out' (x86_64). (lldb) b 13 Breakpoint 1: where = a.out`t1::t1() + 20 at test.cpp:6:7, address = 0x0000000000401174 (lldb) r Process 554103 launched: '/usr/local/google/home/blaikie/dev/scratch/a.out' (x86_64) Process 554103 stopped * thread #1, name = 'a.out', stop reason = breakpoint 1.1 frame #0: 0x0000000000401174 a.out`t1::t1(this=0x000000000040402c) at test.cpp:6:7 3 int // 3 4 i // 4 5 = // 5 -> 6 f1 // 6 7 (); 8 9 (lldb) > > (lldb) target create "./a.out" > > Current executable set to > > '/usr/local/google/home/blaikie/dev/scratch/a.out' (x86_64). > > (lldb) b 1 > > Breakpoint 1: where = a.out`f1() + 4 at break.cpp:1:37, address = > > 0x0000000000401144 > > (lldb) b 2 > > Breakpoint 2: no locations (pending). > > WARNING: Unable to resolve breakpoint to any actual locations. > > (lldb) b 3 > > Breakpoint 3: no locations (pending). > > WARNING: Unable to resolve breakpoint to any actual locations. > > (lldb) b 4 > > Breakpoint 4: no locations (pending). > > WARNING: Unable to resolve breakpoint to any actual locations. > > (lldb) b 5 > > Breakpoint 5: no locations (pending). > > WARNING: Unable to resolve breakpoint to any actual locations. > > (lldb) b 6 > > Breakpoint 6: no locations (pending). > > WARNING: Unable to resolve breakpoint to any actual locations. > > (lldb) b 7 > > Breakpoint 7: where = a.out`t1::t1() + 20 at break.cpp:6:7, address = > > 0x0000000000401174 > > (lldb) b 8 > > Breakpoint 8: where = a.out`t1::t1() + 20 at break.cpp:6:7, address = > > 0x0000000000401174 > > (lldb) b 9 > > Breakpoint 9: where = a.out`t1::t1() + 33 at break.cpp:9:3, address = > > 0x0000000000401181 > > (lldb) r > > > >> BTW, the check wouldn't have affected code from .defs files because I only > >> do it if the original breakpoint specification and the "function start" > >> are from the same source file. > > > > Sure enough - no doubt someone out there has some file that #includes > > itself in some entertaining way, but likely quite rare. > > Given that the penalty you have to pay for such a deed is having to be a > little more careful how you set breakpoints, I don't feel the need for > super-human efforts in this area. > > Jim > > > > > >> And we know about inlined blocks so inlining isn't going to fool us either. > >> > >> Jim > >> > >> > >> > >> > >>> On Jan 15, 2021, at 5:09 PM, David Blaikie <dblai...@gmail.com> wrote: > >>> > >>> "But because their source lines are outside the function source range" > >>> > >>> Not sure I understand that - the DWARF doesn't describe a function > >>> source range, right? Only the line a function starts on. And a > >>> function can have code from source lines in many files/offsets that > >>> are unrelated to the function start line (LLVM in several places > >>> #includes .def files into functions to stamp out tables, switches, > >>> arrays, etc, for instance) > >>> > >>> On Fri, Jan 15, 2021 at 4:47 PM Jim Ingham via Phabricator via > >>> lldb-commits <lldb-commits@lists.llvm.org> wrote: > >>>> > >>>> jingham created this revision. > >>>> jingham requested review of this revision. > >>>> Herald added a project: LLDB. > >>>> Herald added a subscriber: lldb-commits. > >>>> > >>>> The inline initializers contribute code to the constructor(s). You will > >>>> step onto them in the source view as you step through the constructor, > >>>> for instance. But because their source lines are outside the function > >>>> source range, lldb thought a breakpoint on the initializer line was > >>>> crossing from one function to another, which file & line breakpoints > >>>> don't allow. That meant if you tried to set a breakpoint on one of > >>>> these lines it doesn't create any locations. > >>>> > >>>> This patch fixes that by asserting that if the LineEntry in one of the > >>>> SymbolContexts that the search produced exactly matches the file & line > >>>> specifications in the breakpoint, it has to be a valid place to set the > >>>> breakpoint, and we should just set it. > >>>> > >>>> > >>>> Repository: > >>>> rG LLVM Github Monorepo > >>>> > >>>> https://reviews.llvm.org/D94846 > >>>> > >>>> Files: > >>>> lldb/source/Breakpoint/BreakpointResolverFileLine.cpp > >>>> lldb/test/API/lang/cpp/break-on-initializers/Makefile > >>>> lldb/test/API/lang/cpp/break-on-initializers/TestBreakOnCPP11Initializers.py > >>>> lldb/test/API/lang/cpp/break-on-initializers/main.cpp > >>>> > >>>> _______________________________________________ > >>>> lldb-commits mailing list > >>>> lldb-commits@lists.llvm.org > >>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits > _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits