[lldb-dev] lldb fails to hit breakpoint when line maps to multiple addresses
Jim Ingham via lldb-dev
lldb-dev at lists.llvm.org
Wed Oct 7 17:07:41 PDT 2015
> On Oct 7, 2015, at 4:39 PM, dawn at burble.org wrote:
> On Mon, Oct 05, 2015 at 03:01:28PM -0700, Jim Ingham wrote:
>> Given that, the best lldb can do is use heuristics, and the best heuristic I had was Block == basic block???
> Can you at least check for branches then? (Yes, that would require disassembly).
Breakpoint setting doesn't have to be blazingly fast, we look as disassembly and worse in other cases (e.g. resolver symbols actually have to be resolved - which involves a function call in the debugee - to figure out the target of the resolver...) So I'm not opposed to this in general. But I wouldn't want (you ;-)) to do this work if it isn't going to cover all the cases you care about, which it sounds from below like it wouldn't. And you would have to be careful since things like calls shouldn't cause extra locations to be generated...
Another way to do this - which I thought about originally but rejected as too much delicate machinery for the desired effect - is to add the notion of "clusters" of locations to the breakpoint. Instead of eliding all the segments with the same line number into one location, you'd make a location per segment but treat them as a cluster, where a hit on one location in the cluster would set a flag telling you to auto-continue the other locations in the cluster till "something happened to reset the cluster". You'd have to figure out good heuristics for that "something happened". You could probably get away with "frame changed" and "hit the location that I hit the first time I hit the cluster". But I'd have to think a bit harder about this to assure myself this was good enough. And you'd have to keep a side table of history for each breakpoint which you'd have to manage... Nothing impossible, but it didn't seem worth the effort at the time.
Anyway, if you are sufficiently motivated to give this a try, it would be a more general solution to the problem without requiring user intervention - either having to press continue some undetermined number of times, or create the breakpoints with some special option.
>> The motivation is that compilers in general and certainly clang in particular love to put multiple line table entries in for a given line that are either contiguous or interrupted by artificial book-keeping code. So if we didn???t coalesce these line entries, when you set a breakpoint on such a line, you??????d have to hit continue some unpredictable number of times before you actually get past that line. You could figure out how many time by counting the number of locations, but nobody could be expected to do that??? And if you are chasing multiple hits of the breakpoint through code it was really a pain since one ???continue??? didn???t result in one pass through the function containing the code. This happens very frequently and was a font of bugs for lldb early on.
> Understood - we get reports like this all the time, and I've also thought of
> ways to workaround it, but for each idea I had, I could always find a way to
> break it. So now I tell users it "works as designed", and that it's better
> to hit a BP a couple times than none at all.
>> Note, this doesn???t affect the stepping algorithms, since when we step we just look at where we land and if it has the same line number as we were stepping through we keep going. Of course, it also makes stepping over such a line annoying for the same reason that it made continue annoying...
> What about tail recursion? You must at least check the stack ptr, no?
Of course, and not just for tail recursion: the current line might have called something that calls the current function that gets you back to the current line. Stepping can't stop for that either. I wasn't giving a complete description of the stepping algorithm, just how it pertains to passing through blocks of code in the same function.
>> Note also that gdb plays the same trick with setting breakpoints on multiple line table entries (or at least it did last time I looked.) This wasn???t something new in lldb.
> No, gdb gets this case right.
Interesting. Maybe they've changed how they do the line coalescing, I haven't looked in years.
>> Yours is the first report we???ve had where this causes trouble, whereas it makes general stepping work much more nicely.
> I'm quite surprised. FWIW, the typical case we see this in is exception handling.
Maybe you have a different code generation model from clang (or swift?)
>> So if you have some specific reason to need it either (a) if there???s some better heuristic you can come up with that detects when you should not coalesce, that would be awesome
> Better: check for branches out of the block.
> But this would still fail for cases where code branches around the initial block
> and into the blocks belonging to that line further down.
> ; Example pseudo code: Set BP at line 10 in the following:
> br @lbl2 ; belongs to line 9
> lbl1: insns_for_line10_part1 ; lldb sets BP here
> lbl2: insns_for_line10_part2 ; BP at line 10 never hit
> if (false_cond) br @lbl1
> So best would be to also check for labels which lines into the block,
> but that's unrealistic.
>> or (b) if there???s no way lldb can tell, you???ll have to add an option.
> Sounds like we'll have to go with an option then.
Yeah, that sounds like the safest way to go as a short term solution.
More information about the lldb-dev