Skip to content

Commit 54837b1

Browse files
committed
[lldb] Mark scripted frames as synthetic instead of artificial (llvm#153117)
This patch changes the way frames created from scripted affordances like Scripted Threads are displayed. Currently, they're marked artificial which is used usually for compiler generated frames. This patch changes that behaviour by introducing a new synthetic StackFrame kind and moves 'artificial' to be a distinct StackFrame attribut. On top of making these frames less confusing, this allows us to know when a frame was created from a scripted affordance. rdar://155949703 Signed-off-by: Med Ismail Bennani <[email protected]> (cherry picked from commit 6c10ab8) (cherry picked from commit 9a81ba2)
1 parent cf5a10c commit 54837b1

File tree

17 files changed

+156
-109
lines changed

17 files changed

+156
-109
lines changed

lldb/include/lldb/API/SBFrame.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ class LLDB_API SBFrame {
107107

108108
bool IsArtificial() const;
109109

110+
bool IsSynthetic() const;
111+
110112
/// Return whether a frame recognizer decided this frame should not
111113
/// be displayes in backtraces etc.
112114
bool IsHidden() const;

lldb/include/lldb/Core/FormatEntity.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct Entry {
8080
FrameRegisterFlags,
8181
FrameRegisterByName,
8282
FrameIsArtificial,
83+
FrameKind,
8384
ScriptFrame,
8485
FunctionID,
8586
FunctionDidChange,

lldb/include/lldb/Target/StackFrame.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,9 @@ class StackFrame : public ExecutionContextScope,
6060
/// local variables.
6161
History,
6262

63-
/// An artificial stack frame (e.g. a synthesized result of inferring
64-
/// missing tail call frames from a backtrace) with limited support for
65-
/// local variables.
66-
Artificial
63+
/// An synthetic stack frame (e.g. a synthesized result from script
64+
/// resource) possibly without support for local variables or register.
65+
Synthetic
6766
};
6867

6968
/// Construct a StackFrame object without supplying a RegisterContextSP.
@@ -109,7 +108,8 @@ class StackFrame : public ExecutionContextScope,
109108
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx,
110109
lldb::user_id_t concrete_frame_idx, lldb::addr_t cfa,
111110
bool cfa_is_valid, lldb::addr_t pc, Kind frame_kind,
112-
bool behaves_like_zeroth_frame, const SymbolContext *sc_ptr);
111+
bool artificial, bool behaves_like_zeroth_frame,
112+
const SymbolContext *sc_ptr);
113113

114114
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx,
115115
lldb::user_id_t concrete_frame_idx,
@@ -400,6 +400,9 @@ class StackFrame : public ExecutionContextScope,
400400
/// true if this is an inlined frame.
401401
bool IsInlined();
402402

403+
/// Query whether this frame is synthetic.
404+
bool IsSynthetic() const;
405+
403406
/// Query whether this frame is part of a historical backtrace.
404407
bool IsHistorical() const;
405408

@@ -575,6 +578,10 @@ class StackFrame : public ExecutionContextScope,
575578
/// Does this frame have a CFA? Different from CFA == LLDB_INVALID_ADDRESS.
576579
bool m_cfa_is_valid;
577580
Kind m_stack_frame_kind;
581+
/// Is this an artificial stack frame (e.g. a synthesized result of inferring
582+
/// missing tail call frames from a backtrace) with limited support for
583+
/// local variables. Orthogonal to `StackFrame::Kind`.
584+
bool m_artificial;
578585

579586
/// Whether this frame behaves like the zeroth frame, in the sense
580587
/// that its pc value might not immediately follow a call (and thus might

lldb/source/API/SBFrame.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,22 @@ bool SBFrame::IsArtificial() const {
11261126
return false;
11271127
}
11281128

1129+
bool SBFrame::IsSynthetic() const {
1130+
LLDB_INSTRUMENT_VA(this);
1131+
1132+
llvm::Expected<StoppedExecutionContext> exe_ctx =
1133+
GetStoppedExecutionContext(m_opaque_sp);
1134+
if (!exe_ctx) {
1135+
LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
1136+
return false;
1137+
}
1138+
1139+
if (StackFrame *frame = exe_ctx->GetFramePtr())
1140+
return frame->IsSynthetic();
1141+
1142+
return false;
1143+
}
1144+
11291145
bool SBFrame::IsHidden() const {
11301146
LLDB_INSTRUMENT_VA(this);
11311147

lldb/source/Core/CoreProperties.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ let Definition = "debugger" in {
115115
Desc<"The default disassembly format string to use when disassembling instruction sequences.">;
116116
def FrameFormat: Property<"frame-format", "FormatEntity">,
117117
Global,
118-
DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
118+
DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
119119
Desc<"The default frame format string to use when displaying stack frame information for threads.">;
120120
def NotiftVoid: Property<"notify-void", "Boolean">,
121121
Global,
@@ -289,7 +289,7 @@ let Definition = "debugger" in {
289289
Desc<"If true, LLDB will automatically escape non-printable and escape characters when formatting strings.">;
290290
def FrameFormatUnique: Property<"frame-format-unique", "FormatEntity">,
291291
Global,
292-
DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
292+
DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
293293
Desc<"The default frame format string to use when displaying stack frame information for threads from thread backtrace unique.">;
294294
def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">,
295295
Global,

lldb/source/Core/FormatEntity.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ constexpr Definition g_frame_child_entries[] = {
108108
Entry::DefinitionWithChildren("reg", EntryType::FrameRegisterByName,
109109
g_string_entry),
110110
Definition("is-artificial", EntryType::FrameIsArtificial),
111+
Definition("kind", EntryType::FrameKind),
111112
};
112113

113114
constexpr Definition g_function_child_entries[] = {
@@ -380,6 +381,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
380381
ENUM_TO_CSTR(FrameRegisterFlags);
381382
ENUM_TO_CSTR(FrameRegisterByName);
382383
ENUM_TO_CSTR(FrameIsArtificial);
384+
ENUM_TO_CSTR(FrameKind);
383385
ENUM_TO_CSTR(ScriptFrame);
384386
ENUM_TO_CSTR(FunctionID);
385387
ENUM_TO_CSTR(FunctionDidChange);
@@ -1755,6 +1757,18 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
17551757
return false;
17561758
}
17571759

1760+
case Entry::Type::FrameKind: {
1761+
if (exe_ctx)
1762+
if (StackFrame *frame = exe_ctx->GetFramePtr()) {
1763+
if (frame->IsSynthetic())
1764+
s.PutCString(" [synthetic]");
1765+
else if (frame->IsHistorical())
1766+
s.PutCString(" [history]");
1767+
return true;
1768+
}
1769+
return false;
1770+
}
1771+
17581772
case Entry::Type::ScriptFrame:
17591773
if (exe_ctx) {
17601774
StackFrame *frame = exe_ctx->GetFramePtr();

lldb/source/Plugins/Process/scripted/ScriptedThread.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,15 @@ bool ScriptedThread::LoadArtificialStackFrames() {
200200

201201
lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
202202
bool cfa_is_valid = false;
203+
const bool artificial = false;
203204
const bool behaves_like_zeroth_frame = false;
204205
SymbolContext sc;
205206
symbol_addr.CalculateSymbolContext(&sc);
206207

207208
StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
208209
this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
209-
StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);
210+
StackFrame::Kind::Synthetic, artificial, behaves_like_zeroth_frame,
211+
&sc);
210212

211213
if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
212214
return ScriptedInterface::ErrorWithMessage<bool>(

lldb/source/Target/StackFrame.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ using namespace lldb_private;
5858
StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
5959
user_id_t unwind_frame_index, addr_t cfa,
6060
bool cfa_is_valid, addr_t pc, StackFrame::Kind kind,
61-
bool behaves_like_zeroth_frame,
61+
bool artificial, bool behaves_like_zeroth_frame,
6262
const SymbolContext *sc_ptr)
6363
: m_thread_wp(thread_sp), m_frame_index(frame_idx),
6464
m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(),
6565
m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()),
6666
m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
6767
m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
68-
m_stack_frame_kind(kind),
68+
m_stack_frame_kind(kind), m_artificial(artificial),
6969
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
7070
m_variable_list_sp(), m_variable_list_value_objects(),
7171
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
@@ -93,7 +93,7 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
9393
m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()),
9494
m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
9595
m_frame_base_error(), m_cfa_is_valid(true),
96-
m_stack_frame_kind(StackFrame::Kind::Regular),
96+
m_stack_frame_kind(StackFrame::Kind::Regular), m_artificial(false),
9797
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
9898
m_variable_list_sp(), m_variable_list_value_objects(),
9999
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
@@ -121,7 +121,7 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
121121
nullptr, thread_sp->GetProcess().get()),
122122
m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
123123
m_frame_base_error(), m_cfa_is_valid(true),
124-
m_stack_frame_kind(StackFrame::Kind::Regular),
124+
m_stack_frame_kind(StackFrame::Kind::Regular), m_artificial(false),
125125
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
126126
m_variable_list_sp(), m_variable_list_value_objects(),
127127
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
@@ -1305,10 +1305,12 @@ bool StackFrame::IsHistorical() const {
13051305
return m_stack_frame_kind == StackFrame::Kind::History;
13061306
}
13071307

1308-
bool StackFrame::IsArtificial() const {
1309-
return m_stack_frame_kind == StackFrame::Kind::Artificial;
1308+
bool StackFrame::IsSynthetic() const {
1309+
return m_stack_frame_kind == StackFrame::Kind::Synthetic;
13101310
}
13111311

1312+
bool StackFrame::IsArtificial() const { return m_artificial; }
1313+
13121314
bool StackFrame::IsHidden() {
13131315
if (auto recognized_frame_sp = GetRecognizedFrame())
13141316
return recognized_frame_sp->ShouldHide();

lldb/source/Target/StackFrameList.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,14 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
334334
addr_t pc = calleeInfo.address;
335335
// If the callee address refers to the call instruction, we do not want to
336336
// subtract 1 from this value.
337+
const bool artificial = true;
337338
const bool behaves_like_zeroth_frame =
338339
calleeInfo.address_type == CallEdge::AddrType::Call;
339340
SymbolContext sc;
340341
callee->CalculateSymbolContext(&sc);
341342
auto synth_frame = std::make_shared<StackFrame>(
342343
m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,
343-
cfa_is_valid, pc, StackFrame::Kind::Artificial,
344+
cfa_is_valid, pc, StackFrame::Kind::Regular, artificial,
344345
behaves_like_zeroth_frame, &sc);
345346
m_frames.push_back(synth_frame);
346347
LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
@@ -483,7 +484,8 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
483484
const bool cfa_is_valid = true;
484485
unwind_frame_sp = std::make_shared<StackFrame>(
485486
m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid,
486-
pc, StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
487+
pc, StackFrame::Kind::Regular, false, behaves_like_zeroth_frame,
488+
nullptr);
487489

488490
// Create synthetic tail call frames between the previous frame and the
489491
// newly-found frame. The new frame's index may change after this call,

lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,6 @@ def cleanup():
284284
break
285285
self.assertEqual(idx, int(reg.value, 16))
286286

287-
self.assertTrue(frame.IsArtificial(), "Frame is not artificial")
287+
self.assertTrue(frame.IsSynthetic(), "Frame is not synthetic")
288288
pc = frame.GetPCAddress().GetLoadAddress(target_0)
289289
self.assertEqual(pc, 0x0100001B00)

0 commit comments

Comments
 (0)