Skip to content

Commit 0152adf

Browse files
committed
Revert "Revert "Merge pull request swiftlang#9493 from jimingham/swift-call-site-breakpoints""
This reverts commit c93fb6d.
1 parent e09264f commit 0152adf

28 files changed

+759
-147
lines changed

lldb/include/lldb/Breakpoint/BreakpointLocation.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111

1212
#include <memory>
1313
#include <mutex>
14+
#include <optional>
1415

1516
#include "lldb/Breakpoint/BreakpointOptions.h"
1617
#include "lldb/Breakpoint/StoppointHitCounter.h"
1718
#include "lldb/Core/Address.h"
19+
#include "lldb/Symbol/LineEntry.h"
1820
#include "lldb/Utility/UserID.h"
1921
#include "lldb/lldb-private.h"
2022

@@ -282,6 +284,25 @@ class BreakpointLocation
282284
/// Returns the breakpoint location ID.
283285
lldb::break_id_t GetID() const { return m_loc_id; }
284286

287+
/// Set the line entry that should be shown to users for this location.
288+
/// It is up to the caller to verify that this is a valid entry to show.
289+
/// The current use of this is to distinguish among line entries from a
290+
/// virtual inlined call stack that all share the same address.
291+
/// The line entry must have the same start address as the address for this
292+
/// location.
293+
bool SetPreferredLineEntry(const LineEntry &line_entry) {
294+
if (m_address == line_entry.range.GetBaseAddress()) {
295+
m_preferred_line_entry = line_entry;
296+
return true;
297+
}
298+
assert(0 && "Tried to set a preferred line entry with a different address");
299+
return false;
300+
}
301+
302+
const std::optional<LineEntry> GetPreferredLineEntry() {
303+
return m_preferred_line_entry;
304+
}
305+
285306
protected:
286307
friend class BreakpointSite;
287308
friend class BreakpointLocationList;
@@ -306,6 +327,16 @@ class BreakpointLocation
306327
/// If it returns false we should continue, otherwise stop.
307328
bool IgnoreCountShouldStop();
308329

330+
/// If this location knows that the virtual stack frame it represents is
331+
/// not frame 0, return the suggested stack frame instead. This will happen
332+
/// when the location's address contains a "virtual inlined call stack" and
333+
/// the breakpoint was set on a file & line that are not at the bottom of that
334+
/// stack. For now we key off the "preferred line entry" - looking for that
335+
/// in the blocks that start with the stop PC.
336+
/// This version of the API doesn't take an "inlined" parameter because it
337+
/// only changes frames in the inline stack.
338+
std::optional<uint32_t> GetSuggestedStackFrameIndex();
339+
309340
private:
310341
void SwapLocation(lldb::BreakpointLocationSP swap_from);
311342

@@ -369,6 +400,11 @@ class BreakpointLocation
369400
lldb::break_id_t m_loc_id; ///< Breakpoint location ID.
370401
StoppointHitCounter m_hit_counter; ///< Number of times this breakpoint
371402
/// location has been hit.
403+
/// If this exists, use it to print the stop description rather than the
404+
/// LineEntry m_address resolves to directly. Use this for instance when the
405+
/// location was given somewhere in the virtual inlined call stack since the
406+
/// Address always resolves to the lowest entry in the stack.
407+
std::optional<LineEntry> m_preferred_line_entry;
372408

373409
void SetShouldResolveIndirectFunctions(bool do_resolve) {
374410
m_should_resolve_indirect_functions = do_resolve;

lldb/include/lldb/Breakpoint/BreakpointSite.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
170170
/// \see lldb::DescriptionLevel
171171
void GetDescription(Stream *s, lldb::DescriptionLevel level);
172172

173+
// This runs through all the breakpoint locations owning this site and returns
174+
// the greatest of their suggested stack frame indexes. This only handles
175+
// inlined stack changes.
176+
std::optional<uint32_t> GetSuggestedStackFrameIndex();
177+
173178
/// Tell whether a breakpoint has a location at this site.
174179
///
175180
/// \param[in] bp_id

lldb/include/lldb/Core/Declaration.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,14 @@ class Declaration {
8484
/// \param[in] declaration
8585
/// The const Declaration object to compare with.
8686
///
87+
/// \param[in] full
88+
/// Same meaning as Full in FileSpec::Equal. True means an empty
89+
/// directory is not equal to a specified one, false means it is equal.
90+
///
8791
/// \return
8892
/// Returns \b true if \b declaration is at the same file and
8993
/// line, \b false otherwise.
90-
bool FileAndLineEqual(const Declaration &declaration) const;
94+
bool FileAndLineEqual(const Declaration &declaration, bool full) const;
9195

9296
/// Dump a description of this object to a Stream.
9397
///

lldb/include/lldb/Target/StopInfo.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ class StopInfo : public std::enable_shared_from_this<StopInfo> {
7777
m_description.clear();
7878
}
7979

80+
/// This gives the StopInfo a chance to suggest a stack frame to select.
81+
/// Passing true for inlined_stack will request changes to the inlined
82+
/// call stack. Passing false will request changes to the real stack
83+
/// frame. The inlined stack gets adjusted before we call into the thread
84+
/// plans so they can reason based on the correct values. The real stack
85+
/// adjustment is handled after the frame recognizers get a chance to adjust
86+
/// the frame.
87+
virtual std::optional<uint32_t>
88+
GetSuggestedStackFrameIndex(bool inlined_stack) {
89+
return {};
90+
}
91+
8092
virtual bool IsValidForOperatingSystemThread(Thread &thread) { return true; }
8193

8294
/// A Continue operation can result in a false stop event

lldb/include/lldb/Target/ThreadPlanStepInRange.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ class ThreadPlanStepInRange : public ThreadPlanStepRange,
100100
bool m_step_past_prologue; // FIXME: For now hard-coded to true, we could put
101101
// a switch in for this if there's
102102
// demand for that.
103-
bool m_virtual_step; // true if we've just done a "virtual step", i.e. just
104-
// moved the inline stack depth.
103+
LazyBool m_virtual_step; // true if we've just done a "virtual step", i.e.
104+
// just moved the inline stack depth.
105105
ConstString m_step_into_target;
106106
std::vector<lldb::break_id_t> m_step_in_deep_bps; // Places where we might
107107
// want to stop when we do a

lldb/source/Breakpoint/BreakpointLocation.cpp

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,20 @@ void BreakpointLocation::GetDescription(Stream *s,
508508
s->PutCString("re-exported target = ");
509509
else
510510
s->PutCString("where = ");
511+
512+
// If there's a preferred line entry for printing, use that.
513+
bool show_function_info = true;
514+
if (auto preferred = GetPreferredLineEntry()) {
515+
sc.line_entry = *preferred;
516+
// FIXME: We're going to get the function name wrong when the preferred
517+
// line entry is not the lowest one. For now, just leave the function
518+
// out in this case, but we really should also figure out how to easily
519+
// fake the function name here.
520+
show_function_info = false;
521+
}
511522
sc.DumpStopContext(s, m_owner.GetTarget().GetProcessSP().get(), m_address,
512-
false, true, false, true, true, true);
523+
false, true, false, show_function_info,
524+
show_function_info, show_function_info);
513525
} else {
514526
if (sc.module_sp) {
515527
s->EOL();
@@ -537,7 +549,10 @@ void BreakpointLocation::GetDescription(Stream *s,
537549
if (sc.line_entry.line > 0) {
538550
s->EOL();
539551
s->Indent("location = ");
540-
sc.line_entry.DumpStopContext(s, true);
552+
if (auto preferred = GetPreferredLineEntry())
553+
preferred->DumpStopContext(s, true);
554+
else
555+
sc.line_entry.DumpStopContext(s, true);
541556
}
542557

543558
} else {
@@ -656,6 +671,50 @@ void BreakpointLocation::SendBreakpointLocationChangedEvent(
656671
}
657672
}
658673

674+
std::optional<uint32_t> BreakpointLocation::GetSuggestedStackFrameIndex() {
675+
auto preferred_opt = GetPreferredLineEntry();
676+
if (!preferred_opt)
677+
return {};
678+
LineEntry preferred = *preferred_opt;
679+
SymbolContext sc;
680+
if (!m_address.CalculateSymbolContext(&sc))
681+
return {};
682+
// Don't return anything special if frame 0 is the preferred line entry.
683+
// We not really telling the stack frame list to do anything special in that
684+
// case.
685+
if (!LineEntry::Compare(sc.line_entry, preferred))
686+
return {};
687+
688+
if (!sc.block)
689+
return {};
690+
691+
// Blocks have their line info in Declaration form, so make one here:
692+
Declaration preferred_decl(preferred.GetFile(), preferred.line,
693+
preferred.column);
694+
695+
uint32_t depth = 0;
696+
Block *inlined_block = sc.block->GetContainingInlinedBlock();
697+
while (inlined_block) {
698+
// If we've moved to a block that this isn't the start of, that's not
699+
// our inlining info or call site, so we can stop here.
700+
Address start_address;
701+
if (!inlined_block->GetStartAddress(start_address) ||
702+
start_address != m_address)
703+
return {};
704+
705+
const InlineFunctionInfo *info = inlined_block->GetInlinedFunctionInfo();
706+
if (info) {
707+
if (preferred_decl == info->GetDeclaration())
708+
return depth;
709+
if (preferred_decl == info->GetCallSite())
710+
return depth + 1;
711+
}
712+
inlined_block = inlined_block->GetInlinedParent();
713+
depth++;
714+
}
715+
return {};
716+
}
717+
659718
void BreakpointLocation::SwapLocation(BreakpointLocationSP swap_from) {
660719
m_address = swap_from->m_address;
661720
m_should_resolve_indirect_functions =

lldb/source/Breakpoint/BreakpointResolver.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,21 @@ void BreakpointResolver::AddLocation(SearchFilter &filter,
340340
}
341341

342342
BreakpointLocationSP bp_loc_sp(AddLocation(line_start));
343+
// If the address that we resolved the location to returns a different
344+
// LineEntry from the one in the incoming SC, we're probably dealing with an
345+
// inlined call site, so set that as the preferred LineEntry:
346+
LineEntry resolved_entry;
347+
if (!skipped_prologue && bp_loc_sp &&
348+
line_start.CalculateSymbolContextLineEntry(resolved_entry) &&
349+
LineEntry::Compare(resolved_entry, sc.line_entry)) {
350+
// FIXME: The function name will also be wrong here. Do we need to record
351+
// that as well, or can we figure that out again when we report this
352+
// breakpoint location.
353+
if (!bp_loc_sp->SetPreferredLineEntry(sc.line_entry)) {
354+
LLDB_LOG(log, "Tried to add a preferred line entry that didn't have the "
355+
"same address as this location's address.");
356+
}
357+
}
343358
if (log && bp_loc_sp && !GetBreakpoint()->IsInternal()) {
344359
StreamString s;
345360
bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);

lldb/source/Breakpoint/BreakpointSite.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,23 @@ void BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) {
8787
m_constituents.GetDescription(s, level);
8888
}
8989

90+
std::optional<uint32_t> BreakpointSite::GetSuggestedStackFrameIndex() {
91+
92+
std::optional<uint32_t> result;
93+
std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
94+
for (BreakpointLocationSP loc_sp : m_constituents.BreakpointLocations()) {
95+
std::optional<uint32_t> loc_frame_index =
96+
loc_sp->GetSuggestedStackFrameIndex();
97+
if (loc_frame_index) {
98+
if (result)
99+
result = std::max(*loc_frame_index, *result);
100+
else
101+
result = loc_frame_index;
102+
}
103+
}
104+
return result;
105+
}
106+
90107
bool BreakpointSite::IsInternal() const { return m_constituents.IsInternal(); }
91108

92109
uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; }

lldb/source/Core/Declaration.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ int Declaration::Compare(const Declaration &a, const Declaration &b) {
7070
return 0;
7171
}
7272

73-
bool Declaration::FileAndLineEqual(const Declaration &declaration) const {
74-
int file_compare = FileSpec::Compare(this->m_file, declaration.m_file, true);
73+
bool Declaration::FileAndLineEqual(const Declaration &declaration,
74+
bool full) const {
75+
int file_compare = FileSpec::Compare(this->m_file, declaration.m_file, full);
7576
return file_compare == 0 && this->m_line == declaration.m_line;
7677
}
7778

lldb/source/Symbol/Block.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ Block *Block::GetContainingInlinedBlockWithCallSite(
230230
const auto *function_info = inlined_block->GetInlinedFunctionInfo();
231231

232232
if (function_info &&
233-
function_info->GetCallSite().FileAndLineEqual(find_call_site))
233+
function_info->GetCallSite().FileAndLineEqual(find_call_site, true))
234234
return inlined_block;
235235
inlined_block = inlined_block->GetInlinedParent();
236236
}

0 commit comments

Comments
 (0)