Skip to content

Commit bb5a462

Browse files
author
git apple-llvm automerger
committed
Merge commit 'b81995be1318' from swift/release/6.1 into stable/20240723
2 parents fdfa59e + b81995b commit bb5a462

34 files changed

+1133
-331
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/StackFrameList.h

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <memory>
1313
#include <mutex>
14+
#include <shared_mutex>
1415
#include <vector>
1516

1617
#include "lldb/Target/StackFrame.h"
@@ -94,24 +95,36 @@ class StackFrameList {
9495
bool show_unique = false, bool show_hidden = false,
9596
const char *frame_marker = nullptr);
9697

98+
/// Returns whether we have currently fetched all the frames of a stack.
99+
bool WereAllFramesFetched() const;
100+
97101
protected:
98102
friend class Thread;
99103
friend class ScriptedThread;
100104

105+
/// Use this API to build a stack frame list (used for scripted threads, for
106+
/// instance.) This API is not meant for StackFrameLists that have unwinders
107+
/// and partake in lazy stack filling (using GetFramesUpTo). Rather if you
108+
/// are building StackFrameLists with this API, you should build the entire
109+
/// list before making it available for use.
101110
bool SetFrameAtIndex(uint32_t idx, lldb::StackFrameSP &frame_sp);
102111

103-
/// Realizes frames up to (and including) end_idx (which can be greater than
104-
/// the actual number of frames.)
112+
/// Ensures that frames up to (and including) `end_idx` are realized in the
113+
/// StackFrameList. `end_idx` can be larger than the actual number of frames,
114+
/// in which case all the frames will be fetched. Acquires the writer end of
115+
/// the list mutex.
105116
/// Returns true if the function was interrupted, false otherwise.
106-
bool GetFramesUpTo(uint32_t end_idx,
107-
InterruptionControl allow_interrupt = AllowInterruption);
108-
109-
void GetOnlyConcreteFramesUpTo(uint32_t end_idx, Unwind &unwinder);
110-
111-
void SynthesizeTailCallFrames(StackFrame &next_frame);
112-
113-
bool GetAllFramesFetched() { return m_concrete_frames_fetched == UINT32_MAX; }
117+
/// Callers should first check (under the shared mutex) whether we need to
118+
/// fetch frames or not.
119+
bool GetFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
120+
121+
// This should be called with either the reader or writer end of the list
122+
// mutex held:
123+
bool GetAllFramesFetched() const {
124+
return m_concrete_frames_fetched == UINT32_MAX;
125+
}
114126

127+
// This should be called with the writer end of the list mutex held.
115128
void SetAllFramesFetched() { m_concrete_frames_fetched = UINT32_MAX; }
116129

117130
bool DecrementCurrentInlinedDepth();
@@ -122,6 +135,9 @@ class StackFrameList {
122135

123136
void SetCurrentInlinedDepth(uint32_t new_depth);
124137

138+
/// Calls into the stack frame recognizers and stop info to set the most
139+
/// relevant frame. This can call out to arbitrary user code so it can't
140+
/// hold the StackFrameList mutex.
125141
void SelectMostRelevantFrame();
126142

127143
typedef std::vector<lldb::StackFrameSP> collection;
@@ -138,11 +154,16 @@ class StackFrameList {
138154
// source of information.
139155
lldb::StackFrameListSP m_prev_frames_sp;
140156

141-
/// A mutex for this frame list.
142-
// TODO: This mutex may not always be held when required. In particular, uses
143-
// of the StackFrameList APIs in lldb_private::Thread look suspect. Consider
144-
// passing around a lock_guard reference to enforce proper locking.
145-
mutable std::recursive_mutex m_mutex;
157+
/// A mutex for this frame list. The only public API that requires the
158+
/// unique lock is Clear. All other clients take the shared lock, though
159+
/// if we need more frames we may swap shared for unique to fulfill that
160+
/// requirement.
161+
mutable std::shared_mutex m_list_mutex;
162+
163+
// Setting the inlined depth should be protected against other attempts to
164+
// change it, but since it doesn't mutate the list itself, we can limit the
165+
// critical regions it produces by having a separate mutex.
166+
mutable std::mutex m_inlined_depth_mutex;
146167

147168
/// A cache of frames. This may need to be updated when the program counter
148169
/// changes.
@@ -171,6 +192,21 @@ class StackFrameList {
171192
const bool m_show_inlined_frames;
172193

173194
private:
195+
uint32_t SetSelectedFrameNoLock(lldb_private::StackFrame *frame);
196+
lldb::StackFrameSP
197+
GetFrameAtIndexNoLock(uint32_t idx,
198+
std::shared_lock<std::shared_mutex> &guard);
199+
200+
/// These two Fetch frames APIs and SynthesizeTailCallFrames are called in
201+
/// GetFramesUpTo, they are the ones that actually add frames. They must be
202+
/// called with the writer end of the list mutex held.
203+
204+
/// Returns true if fetching frames was interrupted, false otherwise.
205+
bool FetchFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
206+
/// Not currently interruptible so returns void.
207+
void FetchOnlyConcreteFramesUpTo(uint32_t end_idx);
208+
void SynthesizeTailCallFrames(StackFrame &next_frame);
209+
174210
StackFrameList(const StackFrameList &) = delete;
175211
const StackFrameList &operator=(const StackFrameList &) = delete;
176212
};

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/ThreadPlanStack.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <unordered_map>
1515
#include <vector>
1616

17+
#include "llvm/Support/RWMutex.h"
18+
1719
#include "lldb/Target/Target.h"
1820
#include "lldb/Target/Thread.h"
1921
#include "lldb/lldb-private-forward.h"
@@ -102,9 +104,12 @@ class ThreadPlanStack {
102104
void SetTID(lldb::tid_t tid);
103105

104106
private:
105-
void PrintOneStack(Stream &s, llvm::StringRef stack_name,
106-
const PlanStack &stack, lldb::DescriptionLevel desc_level,
107-
bool include_internal) const;
107+
lldb::ThreadPlanSP DiscardPlanNoLock();
108+
lldb::ThreadPlanSP GetCurrentPlanNoLock() const;
109+
void PrintOneStackNoLock(Stream &s, llvm::StringRef stack_name,
110+
const PlanStack &stack,
111+
lldb::DescriptionLevel desc_level,
112+
bool include_internal) const;
108113

109114
PlanStack m_plans; ///< The stack of plans this thread is executing.
110115
PlanStack m_completed_plans; ///< Plans that have been completed by this
@@ -116,8 +121,8 @@ class ThreadPlanStack {
116121
size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for
117122
// completed plan checkpoints.
118123
std::unordered_map<size_t, PlanStack> m_completed_plan_store;
119-
mutable std::recursive_mutex m_stack_mutex;
120-
124+
mutable llvm::sys::RWMutex m_stack_mutex;
125+
121126
// ThreadPlanStacks shouldn't be copied.
122127
ThreadPlanStack(ThreadPlanStack &rhs) = delete;
123128
};

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);

0 commit comments

Comments
 (0)