Skip to content

Commit 3dcce7c

Browse files
committed
[lldb] Add support for the DW_AT_trampoline attribute with a boolean
This patch adds support for the DW_AT_trampoline attribute whose value is a boolean. Which is a "generic trampoline". Stepping into a generic trampoline by default will step through the function, checking at every branch, until we stop in a function which makes sense to stop at (a function with debug info, which isn't a trampoline, for example). Differential Revision: https://reviews.llvm.org/D147292 (cherry picked from commit 4a8e545) (cherry picked from commit 2af4818)
1 parent 8b5fc30 commit 3dcce7c

28 files changed

+499
-43
lines changed

lldb/include/lldb/Symbol/Function.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ class Function : public UserID, public SymbolContextScope {
442442
Function(CompileUnit *comp_unit, lldb::user_id_t func_uid,
443443
lldb::user_id_t func_type_uid, const Mangled &mangled,
444444
Type *func_type, const AddressRange &range,
445-
bool can_throw = false);
445+
bool can_throw = false, bool generic_trampoline = false);
446446

447447
/// Destructor.
448448
~Function() override;
@@ -554,6 +554,10 @@ class Function : public UserID, public SymbolContextScope {
554554
/// A type object pointer.
555555
Type *GetType();
556556

557+
bool IsGenericTrampoline() const {
558+
return m_is_generic_trampoline;
559+
}
560+
557561
/// Get const accessor for the type that describes the function return value
558562
/// type, and parameter types.
559563
///
@@ -659,6 +663,8 @@ class Function : public UserID, public SymbolContextScope {
659663
/// information.
660664
Mangled m_mangled;
661665

666+
bool m_is_generic_trampoline;
667+
662668
/// All lexical blocks contained in this function.
663669
Block m_block;
664670

lldb/include/lldb/Target/Target.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,12 @@ class TargetProperties : public Properties {
289289

290290
bool GetDebugUtilityExpression() const;
291291

292+
/// Trampoline support includes stepping through trampolines directly to their
293+
/// targets, stepping out of trampolines directly to their callers, and
294+
/// automatically filtering out trampolines as possible breakpoint locations
295+
/// when set by name.
296+
bool GetEnableTrampolineSupport() const;
297+
292298
private:
293299
// Callbacks for m_launch_info.
294300
void Arg0ValueChangedCallback();

lldb/include/lldb/Target/Thread.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,27 @@ class Thread : public std::enable_shared_from_this<Thread>,
904904
bool abort_other_plans, bool stop_other_threads,
905905
Status &status);
906906

907+
/// Gets the plan used to step through a function with a generic trampoline. A
908+
/// generic trampoline is one without a function target, which the thread plan
909+
/// will attempt to step through until it finds a place where it makes sense
910+
/// to stop at.
911+
/// \param[in] abort_other_plans
912+
/// \b true if we discard the currently queued plans and replace them with
913+
/// this one.
914+
/// Otherwise this plan will go on the end of the plan stack.
915+
///
916+
/// \param[in] stop_other_threads
917+
/// \b true if we will stop other threads while we single step this one.
918+
///
919+
/// \param[out] status
920+
/// A status with an error if queuing failed.
921+
///
922+
/// \return
923+
/// A shared pointer to the newly queued thread plan, or nullptr if the
924+
/// plan could not be queued.
925+
virtual lldb::ThreadPlanSP QueueThreadPlanForStepThroughGenericTrampoline(
926+
bool abort_other_plans, lldb::RunMode stop_other_threads, Status &status);
927+
907928
/// Gets the plan used to continue from the current PC.
908929
/// This is a simple plan, mostly useful as a backstop when you are continuing
909930
/// for some particular purpose.

lldb/include/lldb/Target/ThreadPlan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
302302
eKindStepInRange,
303303
eKindRunToAddress,
304304
eKindStepThrough,
305+
eKindStepThroughGenericTrampoline,
305306
eKindStepUntil
306307
};
307308

lldb/include/lldb/Target/ThreadPlanStepOverRange.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ class ThreadPlanStepOverRange : public ThreadPlanStepRange,
3030
bool ShouldStop(Event *event_ptr) override;
3131

3232
protected:
33-
bool DoPlanExplainsStop(Event *event_ptr) override;
3433
bool DoWillResume(lldb::StateType resume_state, bool current_plan) override;
3534

3635
void SetFlagsToDefault() override {

lldb/include/lldb/Target/ThreadPlanStepRange.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class ThreadPlanStepRange : public ThreadPlan {
4141
void AddRange(const AddressRange &new_range);
4242

4343
protected:
44+
bool DoPlanExplainsStop(Event *event_ptr) override;
4445
bool InRange();
4546
lldb::FrameComparison CompareCurrentFrameToStartFrame();
4647
bool InSymbol();
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===-- ThreadPlanStepInRange.h ---------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_TARGET_THREADPLANSTEPTHROUGHGENERICTRAMPOLINE_H
10+
#define LLDB_TARGET_THREADPLANSTEPTHROUGHGENERICTRAMPOLINE_H
11+
12+
#include "lldb/Target/Thread.h"
13+
#include "lldb/Target/ThreadPlanShouldStopHere.h"
14+
#include "lldb/Target/ThreadPlanStepRange.h"
15+
16+
namespace lldb_private {
17+
18+
class ThreadPlanStepThroughGenericTrampoline : public ThreadPlanStepRange,
19+
public ThreadPlanShouldStopHere {
20+
public:
21+
ThreadPlanStepThroughGenericTrampoline(Thread &thread,
22+
lldb::RunMode stop_others);
23+
24+
~ThreadPlanStepThroughGenericTrampoline() override;
25+
26+
void GetDescription(Stream *s, lldb::DescriptionLevel level) override;
27+
28+
bool ShouldStop(Event *event_ptr) override;
29+
bool ValidatePlan(Stream *error) override;
30+
31+
protected:
32+
void SetFlagsToDefault() override {
33+
GetFlags().Set(
34+
ThreadPlanStepThroughGenericTrampoline::s_default_flag_values);
35+
}
36+
37+
private:
38+
// Need an appropriate marker for the current stack so we can tell step out
39+
// from step in.
40+
41+
static uint32_t
42+
s_default_flag_values; // These are the default flag values
43+
// for the ThreadPlanStepThroughGenericTrampoline.
44+
ThreadPlanStepThroughGenericTrampoline(
45+
const ThreadPlanStepThroughGenericTrampoline &) = delete;
46+
const ThreadPlanStepThroughGenericTrampoline &
47+
operator=(const ThreadPlanStepThroughGenericTrampoline &) = delete;
48+
};
49+
50+
} // namespace lldb_private
51+
52+
#endif // LLDB_TARGET_THREADPLANSTEPTHROUGHGENERICTRAMPOLINE_H

lldb/source/Core/Module.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,12 @@ void Module::LookupInfo::Prune(SymbolContextList &sc_list,
805805
if (!sc_list.GetContextAtIndex(i, sc))
806806
break;
807807

808+
bool is_trampoline =
809+
Target::GetGlobalProperties().GetEnableTrampolineSupport() &&
810+
sc.function && sc.function->IsGenericTrampoline();
811+
808812
bool keep_it =
813+
!is_trampoline &&
809814
NameMatchesLookupInfo(sc.GetFunctionName(), sc.GetLanguage());
810815
if (keep_it)
811816
++i;

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2440,12 +2440,16 @@ DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit,
24402440

24412441
assert(func_type == nullptr || func_type != DIE_IS_BEING_PARSED);
24422442

2443+
bool is_generic_trampoline = die.IsGenericTrampoline();
2444+
24432445
const user_id_t func_user_id = die.GetID();
24442446
func_sp =
24452447
std::make_shared<Function>(&comp_unit,
24462448
func_user_id, // UserID is the DIE offset
24472449
func_user_id, func_name, func_type,
2448-
func_range); // first address range
2450+
func_range, // first address range
2451+
false, // canThrow
2452+
is_generic_trampoline);
24492453

24502454
if (func_sp.get() != nullptr) {
24512455
if (frame_base.IsValid())

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,11 @@ Function *DWARFASTParserSwift::ParseFunctionFromDWARF(
274274
decl_column));
275275

276276
const user_id_t func_user_id = die.GetID();
277+
bool is_generic_trampoline = die.IsGenericTrampoline();
277278
func_sp.reset(new Function(&comp_unit, func_user_id, func_user_id,
278-
func_name, nullptr, func_range,
279-
can_throw)); // first address range
279+
func_name, nullptr,
280+
func_range, // first address range
281+
can_throw, is_generic_trampoline));
280282

281283
if (func_sp.get() != NULL) {
282284
if (frame_base.IsValid())

lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,13 @@ const char *DWARFDIE::GetMangledName() const {
203203
return nullptr;
204204
}
205205

206+
bool DWARFDIE::IsGenericTrampoline() const {
207+
if (IsValid())
208+
return m_die->GetIsGenericTrampoline(m_cu);
209+
else
210+
return false;
211+
}
212+
206213
const char *DWARFDIE::GetPubname() const {
207214
if (IsValid())
208215
return m_die->GetPubname(m_cu);

lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class DWARFDIE : public DWARFBaseDIE {
2828
// Accessing information about a DIE
2929
const char *GetMangledName() const;
3030

31+
bool IsGenericTrampoline() const;
32+
3133
const char *GetPubname() const;
3234

3335
using DWARFBaseDIE::GetName;

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,12 @@ DWARFDebugInfoEntry::GetMangledName(const DWARFUnit *cu,
685685
return name;
686686
}
687687

688+
bool
689+
DWARFDebugInfoEntry::GetIsGenericTrampoline(const DWARFUnit *cu) const {
690+
DWARFFormValue form_value;
691+
return GetAttributeValue(cu, DW_AT_trampoline, form_value, nullptr, true) != 0;
692+
}
693+
688694
// GetPubname
689695
//
690696
// Get value the name for a DIE as it should appear for a .debug_pubnames or

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ class DWARFDebugInfoEntry {
9999
const char *GetMangledName(const DWARFUnit *cu,
100100
bool substitute_name_allowed = true) const;
101101

102+
bool GetIsGenericTrampoline(const DWARFUnit *cu) const;
103+
102104
const char *GetPubname(const DWARFUnit *cu) const;
103105

104106
bool GetDIENamesAndRanges(

lldb/source/Symbol/Function.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,11 @@ Function *IndirectCallEdge::GetCallee(ModuleList &images,
233233
//
234234
Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid,
235235
lldb::user_id_t type_uid, const Mangled &mangled, Type *type,
236-
const AddressRange &range, bool canThrow)
236+
const AddressRange &range, bool canThrow, bool is_generic_trampoline)
237237
: UserID(func_uid), m_comp_unit(comp_unit), m_type_uid(type_uid),
238-
m_type(type), m_mangled(mangled), m_block(func_uid), m_range(range),
239-
m_frame_base(), m_flags(), m_prologue_byte_size(0) {
238+
m_type(type), m_mangled(mangled),
239+
m_is_generic_trampoline(is_generic_trampoline), m_block(func_uid),
240+
m_range(range), m_frame_base(), m_flags(), m_prologue_byte_size(0) {
240241
m_block.SetParentScope(this);
241242
if (canThrow)
242243
m_flags.Set(flagsFunctionCanThrow);

lldb/source/Target/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ add_lldb_library(lldbTarget
6666
ThreadPlanStepOverRange.cpp
6767
ThreadPlanStepRange.cpp
6868
ThreadPlanStepThrough.cpp
69+
ThreadPlanStepThroughGenericTrampoline.cpp
6970
ThreadPlanStepUntil.cpp
7071
ThreadPlanTracer.cpp
7172
ThreadPlanStack.cpp

lldb/source/Target/Target.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5305,6 +5305,12 @@ bool TargetProperties::GetDebugUtilityExpression() const {
53055305
nullptr, idx, g_target_properties[idx].default_uint_value != 0);
53065306
}
53075307

5308+
bool TargetProperties::GetEnableTrampolineSupport() const {
5309+
const uint32_t idx = ePropertyEnableTrampolineSupport;
5310+
return m_collection_sp->GetPropertyAtIndexAsBoolean(
5311+
nullptr, idx, g_target_properties[idx].default_uint_value != 0);
5312+
}
5313+
53085314
void TargetProperties::SetDebugUtilityExpression(bool debug) {
53095315
const uint32_t idx = ePropertyDebugUtilityExpression;
53105316
m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, debug);

lldb/source/Target/TargetProperties.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ let Definition = "target" in {
218218
def DebugUtilityExpression: Property<"debug-utility-expression", "Boolean">,
219219
DefaultFalse,
220220
Desc<"Enable debugging of LLDB-internal utility expressions.">;
221+
def EnableTrampolineSupport: Property<"enable-trampoline-support", "Boolean">,
222+
Global, DefaultTrue,
223+
Desc<"Enable trampoline support in LLDB. Trampoline support includes stepping through trampolines directly to their targets, stepping out of trampolines directly to their callers, and automatically filtering out trampolines as possible breakpoint locations when set by name.">;
221224
}
222225

223226
let Definition = "process_experimental" in {

lldb/source/Target/Thread.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
4242
#include "lldb/Target/ThreadPlanStepOverRange.h"
4343
#include "lldb/Target/ThreadPlanStepThrough.h"
44+
#include "lldb/Target/ThreadPlanStepThroughGenericTrampoline.h"
4445
#include "lldb/Target/ThreadPlanStepUntil.h"
4546
#include "lldb/Target/ThreadSpec.h"
4647
#include "lldb/Target/UnwindLLDB.h"
@@ -1420,6 +1421,17 @@ ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id,
14201421
return thread_plan_sp;
14211422
}
14221423

1424+
ThreadPlanSP Thread::QueueThreadPlanForStepThroughGenericTrampoline(
1425+
bool abort_other_plans, lldb::RunMode stop_other_threads, Status &status) {
1426+
ThreadPlanSP thread_plan_sp(
1427+
new ThreadPlanStepThroughGenericTrampoline(*this, stop_other_threads));
1428+
1429+
if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(nullptr))
1430+
return ThreadPlanSP();
1431+
status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
1432+
return thread_plan_sp;
1433+
}
1434+
14231435
ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(bool abort_other_plans,
14241436
Address &target_addr,
14251437
bool stop_other_threads,

lldb/source/Target/ThreadPlanShouldStopHere.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/Target/ThreadPlanShouldStopHere.h"
10+
#include "lldb/Symbol/Function.h"
1011
#include "lldb/Symbol/Symbol.h"
1112
#include "lldb/Target/LanguageRuntime.h"
1213
#include "lldb/Target/Process.h"
@@ -96,10 +97,16 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
9697
// independently. If this ever
9798
// becomes expensive (this one isn't) we can try to have this set a state
9899
// that the StepFromHere can use.
99-
if (frame) {
100-
SymbolContext sc;
101-
sc = frame->GetSymbolContext(eSymbolContextLineEntry);
102-
if (sc.line_entry.line == 0)
100+
SymbolContext sc;
101+
sc = frame->GetSymbolContext(eSymbolContextLineEntry);
102+
103+
if (sc.line_entry.line == 0)
104+
should_stop_here = false;
105+
106+
// If we're in a trampoline, don't stop by default.
107+
if (Target::GetGlobalProperties().GetEnableTrampolineSupport()) {
108+
sc = frame->GetSymbolContext(lldb::eSymbolContextFunction);
109+
if (sc.function && sc.function->IsGenericTrampoline())
103110
should_stop_here = false;
104111
}
105112

lldb/source/Target/ThreadPlanStepInRange.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
221221

222222
// We may have set the plan up above in the FrameIsOlder section:
223223

224+
if (!m_sub_plan_sp)
225+
m_sub_plan_sp = thread.QueueThreadPlanForStepThroughGenericTrampoline(
226+
false, m_stop_others, m_status);
227+
if (log) {
228+
if (m_sub_plan_sp)
229+
LLDB_LOGF(log, "Found a generic step through plan: %s",
230+
m_sub_plan_sp->GetName());
231+
else
232+
LLDB_LOGF(log, "No generic step through plan found.");
233+
}
234+
224235
if (!m_sub_plan_sp)
225236
m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
226237
m_stack_id, false, stop_others, m_status);

lldb/source/Target/ThreadPlanStepOverRange.cpp

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -334,37 +334,6 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
334334
return false;
335335
}
336336

337-
bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
338-
// For crashes, breakpoint hits, signals, etc, let the base plan (or some
339-
// plan above us) handle the stop. That way the user can see the stop, step
340-
// around, and then when they are done, continue and have their step
341-
// complete. The exception is if we've hit our "run to next branch"
342-
// breakpoint. Note, unlike the step in range plan, we don't mark ourselves
343-
// complete if we hit an unexplained breakpoint/crash.
344-
345-
Log *log = GetLog(LLDBLog::Step);
346-
StopInfoSP stop_info_sp = GetPrivateStopInfo();
347-
bool return_value;
348-
349-
if (stop_info_sp) {
350-
StopReason reason = stop_info_sp->GetStopReason();
351-
352-
if (reason == eStopReasonTrace) {
353-
return_value = true;
354-
} else if (reason == eStopReasonBreakpoint) {
355-
return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
356-
} else {
357-
if (log)
358-
log->PutCString("ThreadPlanStepInRange got asked if it explains the "
359-
"stop for some reason other than step.");
360-
return_value = false;
361-
}
362-
} else
363-
return_value = true;
364-
365-
return return_value;
366-
}
367-
368337
bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
369338
bool current_plan) {
370339
if (resume_state != eStateSuspended && m_first_resume) {

0 commit comments

Comments
 (0)