Skip to content

Commit 2af4818

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)
1 parent 9f1a8d7 commit 2af4818

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
@@ -799,7 +799,12 @@ void Module::LookupInfo::Prune(SymbolContextList &sc_list,
799799
if (!sc_list.GetContextAtIndex(i, sc))
800800
break;
801801

802+
bool is_trampoline =
803+
Target::GetGlobalProperties().GetEnableTrampolineSupport() &&
804+
sc.function && sc.function->IsGenericTrampoline();
805+
802806
bool keep_it =
807+
!is_trampoline &&
803808
NameMatchesLookupInfo(sc.GetFunctionName(), sc.GetLanguage());
804809
if (keep_it)
805810
++i;

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

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

23962396
assert(func_type == nullptr || func_type != DIE_IS_BEING_PARSED);
23972397

2398+
bool is_generic_trampoline = die.IsGenericTrampoline();
2399+
23982400
const user_id_t func_user_id = die.GetID();
23992401
func_sp =
24002402
std::make_shared<Function>(&comp_unit,
24012403
func_user_id, // UserID is the DIE offset
24022404
func_user_id, func_name, func_type,
2403-
func_range); // first address range
2405+
func_range, // first address range
2406+
false, // canThrow
2407+
is_generic_trampoline);
24042408

24052409
if (func_sp.get() != nullptr) {
24062410
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
const char *GetQualifiedName(std::string &storage) const;

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,12 @@ DWARFDebugInfoEntry::GetMangledName(const DWARFUnit *cu,
679679
return name;
680680
}
681681

682+
bool
683+
DWARFDebugInfoEntry::GetIsGenericTrampoline(const DWARFUnit *cu) const {
684+
DWARFFormValue form_value;
685+
return GetAttributeValue(cu, DW_AT_trampoline, form_value, nullptr, true) != 0;
686+
}
687+
682688
// GetPubname
683689
//
684690
// 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
@@ -97,6 +97,8 @@ class DWARFDebugInfoEntry {
9797
const char *GetMangledName(const DWARFUnit *cu,
9898
bool substitute_name_allowed = true) const;
9999

100+
bool GetIsGenericTrampoline(const DWARFUnit *cu) const;
101+
100102
const char *GetPubname(const DWARFUnit *cu) const;
101103

102104
const char *GetQualifiedName(DWARFUnit *cu, std::string &storage) const;

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
@@ -65,6 +65,7 @@ add_lldb_library(lldbTarget
6565
ThreadPlanStepOverRange.cpp
6666
ThreadPlanStepRange.cpp
6767
ThreadPlanStepThrough.cpp
68+
ThreadPlanStepThroughGenericTrampoline.cpp
6869
ThreadPlanStepUntil.cpp
6970
ThreadPlanTracer.cpp
7071
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"
@@ -1419,6 +1420,17 @@ ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id,
14191420
return thread_plan_sp;
14201421
}
14211422

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