Skip to content

Commit 4a8e545

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
1 parent b24e290 commit 4a8e545

27 files changed

+492
-68
lines changed

lldb/include/lldb/Symbol/Function.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,9 +436,14 @@ class Function : public UserID, public SymbolContextScope {
436436
///
437437
/// \param[in] range
438438
/// The section offset based address for this function.
439+
/// \param[in] generic_trampoline
440+
/// If this function is a generic trampoline. A generic trampoline
441+
/// is a function without any annotations on what the trampoline
442+
/// target is.
439443
Function(CompileUnit *comp_unit, lldb::user_id_t func_uid,
440444
lldb::user_id_t func_type_uid, const Mangled &mangled,
441-
Type *func_type, const AddressRange &range);
445+
Type *func_type, const AddressRange &range,
446+
bool generic_trampoline = false);
442447

443448
/// Destructor.
444449
~Function() override;
@@ -550,6 +555,10 @@ class Function : public UserID, public SymbolContextScope {
550555
/// A type object pointer.
551556
Type *GetType();
552557

558+
bool IsGenericTrampoline() const {
559+
return m_is_generic_trampoline;
560+
}
561+
553562
/// Get const accessor for the type that describes the function return value
554563
/// type, and parameter types.
555564
///
@@ -650,6 +659,8 @@ class Function : public UserID, public SymbolContextScope {
650659
/// information.
651660
Mangled m_mangled;
652661

662+
bool m_is_generic_trampoline;
663+
653664
/// All lexical blocks contained in this function.
654665
Block m_block;
655666

lldb/include/lldb/Target/Target.h

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

251251
bool GetDebugUtilityExpression() const;
252252

253+
/// Trampoline support includes stepping through trampolines directly to their
254+
/// targets, stepping out of trampolines directly to their callers, and
255+
/// automatically filtering out trampolines as possible breakpoint locations
256+
/// when set by name.
257+
bool GetEnableTrampolineSupport() const;
258+
253259
private:
254260
// Callbacks for m_launch_info.
255261
void Arg0ValueChangedCallback();

lldb/include/lldb/Target/Thread.h

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

900+
/// Gets the plan used to step through a function with a generic trampoline. A
901+
/// generic trampoline is one without a function target, which the thread plan
902+
/// will attempt to step through until it finds a place where it makes sense
903+
/// to stop at.
904+
/// \param[in] abort_other_plans
905+
/// \b true if we discard the currently queued plans and replace them with
906+
/// this one.
907+
/// Otherwise this plan will go on the end of the plan stack.
908+
///
909+
/// \param[in] stop_other_threads
910+
/// \b true if we will stop other threads while we single step this one.
911+
///
912+
/// \param[out] status
913+
/// A status with an error if queuing failed.
914+
///
915+
/// \return
916+
/// A shared pointer to the newly queued thread plan, or nullptr if the
917+
/// plan could not be queued.
918+
virtual lldb::ThreadPlanSP QueueThreadPlanForStepThroughGenericTrampoline(
919+
bool abort_other_plans, lldb::RunMode stop_other_threads, Status &status);
920+
900921
/// Gets the plan used to continue from the current PC.
901922
/// This is a simple plan, mostly useful as a backstop when you are continuing
902923
/// 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
@@ -776,7 +776,12 @@ void Module::LookupInfo::Prune(SymbolContextList &sc_list,
776776
if (!sc_list.GetContextAtIndex(i, sc))
777777
break;
778778

779+
bool is_trampoline =
780+
Target::GetGlobalProperties().GetEnableTrampolineSupport() &&
781+
sc.function && sc.function->IsGenericTrampoline();
782+
779783
bool keep_it =
784+
!is_trampoline &&
780785
NameMatchesLookupInfo(sc.GetFunctionName(), sc.GetLanguage());
781786
if (keep_it)
782787
++i;

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2440,12 +2440,15 @@ 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+
is_generic_trampoline);
24492452

24502453
if (func_sp.get() != nullptr) {
24512454
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) != 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
@@ -231,10 +231,11 @@ Function *IndirectCallEdge::GetCallee(ModuleList &images,
231231
//
232232
Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid,
233233
lldb::user_id_t type_uid, const Mangled &mangled, Type *type,
234-
const AddressRange &range)
234+
const AddressRange &range, bool is_generic_trampoline)
235235
: UserID(func_uid), m_comp_unit(comp_unit), m_type_uid(type_uid),
236-
m_type(type), m_mangled(mangled), m_block(func_uid), m_range(range),
237-
m_frame_base(), m_flags(), m_prologue_byte_size(0) {
236+
m_type(type), m_mangled(mangled),
237+
m_is_generic_trampoline(is_generic_trampoline), m_block(func_uid),
238+
m_range(range), m_frame_base(), m_flags(), m_prologue_byte_size(0) {
238239
m_block.SetParentScope(this);
239240
assert(comp_unit != nullptr);
240241
}

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
@@ -4770,6 +4770,12 @@ bool TargetProperties::GetDebugUtilityExpression() const {
47704770
nullptr, idx, g_target_properties[idx].default_uint_value != 0);
47714771
}
47724772

4773+
bool TargetProperties::GetEnableTrampolineSupport() const {
4774+
const uint32_t idx = ePropertyEnableTrampolineSupport;
4775+
return m_collection_sp->GetPropertyAtIndexAsBoolean(
4776+
nullptr, idx, g_target_properties[idx].default_uint_value != 0);
4777+
}
4778+
47734779
void TargetProperties::SetDebugUtilityExpression(bool debug) {
47744780
const uint32_t idx = ePropertyDebugUtilityExpression;
47754781
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
@@ -182,6 +182,9 @@ let Definition = "target" in {
182182
def DebugUtilityExpression: Property<"debug-utility-expression", "Boolean">,
183183
DefaultFalse,
184184
Desc<"Enable debugging of LLDB-internal utility expressions.">;
185+
def EnableTrampolineSupport: Property<"enable-trampoline-support", "Boolean">,
186+
Global, DefaultTrue,
187+
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.">;
185188
}
186189

187190
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"
@@ -1368,6 +1369,17 @@ ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id,
13681369
return thread_plan_sp;
13691370
}
13701371

1372+
ThreadPlanSP Thread::QueueThreadPlanForStepThroughGenericTrampoline(
1373+
bool abort_other_plans, lldb::RunMode stop_other_threads, Status &status) {
1374+
ThreadPlanSP thread_plan_sp(
1375+
new ThreadPlanStepThroughGenericTrampoline(*this, stop_other_threads));
1376+
1377+
if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(nullptr))
1378+
return ThreadPlanSP();
1379+
status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
1380+
return thread_plan_sp;
1381+
}
1382+
13711383
ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(bool abort_other_plans,
13721384
Address &target_addr,
13731385
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/RegisterContext.h"
1213
#include "lldb/Target/Thread.h"
@@ -81,10 +82,16 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
8182
// independently. If this ever
8283
// becomes expensive (this one isn't) we can try to have this set a state
8384
// that the StepFromHere can use.
84-
if (frame) {
85-
SymbolContext sc;
86-
sc = frame->GetSymbolContext(eSymbolContextLineEntry);
87-
if (sc.line_entry.line == 0)
85+
SymbolContext sc;
86+
sc = frame->GetSymbolContext(eSymbolContextLineEntry);
87+
88+
if (sc.line_entry.line == 0)
89+
should_stop_here = false;
90+
91+
// If we're in a trampoline, don't stop by default.
92+
if (Target::GetGlobalProperties().GetEnableTrampolineSupport()) {
93+
sc = frame->GetSymbolContext(lldb::eSymbolContextFunction);
94+
if (sc.function && sc.function->IsGenericTrampoline())
8895
should_stop_here = false;
8996
}
9097

lldb/source/Target/ThreadPlanStepInRange.cpp

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,17 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
217217

218218
// We may have set the plan up above in the FrameIsOlder section:
219219

220+
if (!m_sub_plan_sp)
221+
m_sub_plan_sp = thread.QueueThreadPlanForStepThroughGenericTrampoline(
222+
false, m_stop_others, m_status);
223+
if (log) {
224+
if (m_sub_plan_sp)
225+
LLDB_LOGF(log, "Found a generic step through plan: %s",
226+
m_sub_plan_sp->GetName());
227+
else
228+
LLDB_LOGF(log, "No generic step through plan found.");
229+
}
230+
220231
if (!m_sub_plan_sp)
221232
m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
222233
m_stack_id, false, stop_others, m_status);
@@ -428,33 +439,7 @@ bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) {
428439
// branch" in which case if we hit our branch breakpoint we don't set the
429440
// plan to complete.
430441

431-
bool return_value = false;
432-
433-
if (m_virtual_step) {
434-
return_value = true;
435-
} else {
436-
StopInfoSP stop_info_sp = GetPrivateStopInfo();
437-
if (stop_info_sp) {
438-
StopReason reason = stop_info_sp->GetStopReason();
439-
440-
if (reason == eStopReasonBreakpoint) {
441-
if (NextRangeBreakpointExplainsStop(stop_info_sp)) {
442-
return_value = true;
443-
}
444-
} else if (IsUsuallyUnexplainedStopReason(reason)) {
445-
Log *log = GetLog(LLDBLog::Step);
446-
if (log)
447-
log->PutCString("ThreadPlanStepInRange got asked if it explains the "
448-
"stop for some reason other than step.");
449-
return_value = false;
450-
} else {
451-
return_value = true;
452-
}
453-
} else
454-
return_value = true;
455-
}
456-
457-
return return_value;
442+
return m_virtual_step || ThreadPlanStepRange::DoPlanExplainsStop(event_ptr);
458443
}
459444

460445
bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state,

0 commit comments

Comments
 (0)