Skip to content

Commit b88dc63

Browse files
authored
Merge pull request #6565 from augusto2112/cherry-pick-trampoline-support
Cherry pick trampoline support
2 parents f72221d + 2af4818 commit b88dc63

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+737
-50
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,12 @@ def Artificial : InheritableAttr {
771771
let SimpleHandler = 1;
772772
}
773773

774+
def TransparentStepping: InheritableAttr {
775+
let Spellings = [Clang<"transparent_stepping">];
776+
let Subjects = SubjectList<[Function]>;
777+
let Documentation = [TransparentSteppingDocs];
778+
}
779+
774780
def XRayInstrument : InheritableAttr {
775781
let Spellings = [Clang<"xray_always_instrument">,
776782
Clang<"xray_never_instrument">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6924,6 +6924,66 @@ As such, this function attribute is currently only supported on X86 targets.
69246924
}];
69256925
}
69266926

6927+
def TransparentSteppingDocs : Documentation {
6928+
let Category = DocCatFunction;
6929+
let Content = [{
6930+
The ``transparent_stepping`` attribute is intended as a hint for debuggers that this
6931+
function itself is not interesting, but it calls a function that might be. So, when
6932+
stepping in arrives at a function with this attribute, debuggers should transparently
6933+
step-in through it into the functions called by the annotated function (but not by
6934+
subsequent calls made by those functions), stopping at the first one its normal rules
6935+
for whether to stop says to stop at - or stepping out again if none qualify. Also, when
6936+
stepping out arrives at a function with this attribute, the debugger should continue
6937+
stepping out to its caller.
6938+
6939+
For example:
6940+
6941+
.. code-block:: c
6942+
6943+
int bar(void) {
6944+
return 42;
6945+
}
6946+
6947+
__attribute__((transparent_stepping))
6948+
int foo(void) {
6949+
return bar();
6950+
}
6951+
6952+
int caller(void) {
6953+
return foo();
6954+
}
6955+
6956+
Stepping into ``foo`` should step directly into ``bar`` instead, and stepping out of ``bar``
6957+
should stop in ``caller``.
6958+
6959+
Functions with the ``transparent_stepping`` attribute can be chained together:
6960+
6961+
.. code-block:: c
6962+
6963+
int baz(void) {
6964+
return 42;
6965+
}
6966+
6967+
__attribute__((transparent_stepping))
6968+
int bar(void) {
6969+
return baz();
6970+
}
6971+
6972+
__attribute__((transparent_stepping))
6973+
int foo(void) {
6974+
return bar();
6975+
}
6976+
6977+
int caller(void) {
6978+
return foo();
6979+
}
6980+
6981+
In this example, stepping into ``foo`` should step directly into ``baz``, and stepping out of
6982+
``baz`` should stop in ``caller``.
6983+
}];
6984+
}
6985+
6986+
69276987
def ReadOnlyPlacementDocs : Documentation {
69286988
let Category = DocCatType;
69296989
let Content = [{This attribute is attached to a structure, class or union declaration.

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
6767
return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
6868
}
6969

70+
static bool getIsTransparentStepping(const Decl *D) {
71+
if (!D)
72+
return false;
73+
return D->hasAttr<TransparentSteppingAttr>();
74+
}
75+
7076
CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
7177
: CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
7278
DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
@@ -1882,6 +1888,8 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
18821888
SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
18831889
if (CGM.getLangOpts().Optimize)
18841890
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
1891+
if (getIsTransparentStepping(Method))
1892+
SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping;
18851893

18861894
// In this debug mode, emit type info for a class when its constructor type
18871895
// info is emitted.
@@ -3809,6 +3817,8 @@ llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD,
38093817
if (Stub) {
38103818
Flags |= getCallSiteRelatedAttrs();
38113819
SPFlags |= llvm::DISubprogram::SPFlagDefinition;
3820+
if (getIsTransparentStepping(FD))
3821+
SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping;
38123822
return DBuilder.createFunction(
38133823
DContext, Name, LinkageName, Unit, Line,
38143824
getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags,
@@ -3958,6 +3968,8 @@ llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration(
39583968
if (It == TypeCache.end())
39593969
return nullptr;
39603970
auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
3971+
if (getIsTransparentStepping(D))
3972+
SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping;
39613973
llvm::DISubprogram *FD = DBuilder.createFunction(
39623974
InterfaceType, getObjCMethodName(OMD), StringRef(),
39633975
InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags);
@@ -4124,6 +4136,8 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc,
41244136
SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
41254137
if (CGM.getLangOpts().Optimize)
41264138
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
4139+
if (getIsTransparentStepping(D))
4140+
SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping;
41274141

41284142
llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs();
41294143
llvm::DISubprogram::DISPFlags SPFlagsForDef =
@@ -4210,6 +4224,9 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
42104224

42114225
llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D);
42124226
llvm::DISubroutineType *STy = getOrCreateFunctionType(D, FnType, Unit);
4227+
if (getIsTransparentStepping(D))
4228+
SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping;
4229+
42134230
llvm::DISubprogram *SP = DBuilder.createFunction(
42144231
FDContext, Name, LinkageName, Unit, LineNo, STy, ScopeLine, Flags,
42154232
SPFlags, TParamsArray.get(), nullptr, nullptr, Annotations);

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6687,6 +6687,12 @@ static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) {
66876687
D->addAttr(::new (S.Context) SwiftAsyncNameAttr(S.Context, AL, Name));
66886688
}
66896689

6690+
static void handleTransparentStepping(Sema &S, Decl *D,
6691+
const ParsedAttr &AL) {
6692+
D->addAttr(::new (S.Context)
6693+
TransparentSteppingAttr(S.Context, AL));
6694+
}
6695+
66906696
static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) {
66916697
// Make sure that there is an identifier as the annotation's single argument.
66926698
if (!AL.checkExactlyNumArgs(S, 1))
@@ -8948,6 +8954,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
89488954
case ParsedAttr::AT_NoDebug:
89498955
handleNoDebugAttr(S, D, AL);
89508956
break;
8957+
case ParsedAttr::AT_TransparentStepping:
8958+
handleTransparentStepping(S, D, AL);
8959+
break;
89518960
case ParsedAttr::AT_CmseNSEntry:
89528961
handleCmseNSEntryAttr(S, D, AL);
89538962
break;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
2+
3+
void bar(void) {}
4+
5+
struct A {
6+
[[clang::transparent_stepping()]]
7+
void foo(void) {
8+
bar();
9+
}
10+
};
11+
12+
int main() {
13+
A().foo();
14+
}
15+
16+
// CHECK: DISubprogram(name: "foo"{{.*}} DISPFlagIsTransparentStepping
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
2+
3+
void bar(void) {}
4+
5+
__attribute__((transparent_stepping))
6+
void foo(void) {
7+
bar();
8+
}
9+
10+
// CHECK: DISubprogram(name: "foo"{{.*}} DISPFlagIsTransparentStepping

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
// CHECK-NEXT: Target (SubjectMatchRule_function)
186186
// CHECK-NEXT: TargetClones (SubjectMatchRule_function)
187187
// CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member)
188+
// CHECK-NEXT: TransparentStepping (SubjectMatchRule_function)
188189
// CHECK-NEXT: TrivialABI (SubjectMatchRule_record)
189190
// CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local)
190191
// CHECK-NEXT: UseHandle (SubjectMatchRule_variable_is_parameter)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %clang_cc1 %s -verify -fsyntax-only
2+
3+
__attribute__((transparent_stepping))
4+
void correct(void) {}
5+
6+
__attribute__((transparent_stepping(1))) // expected-error {{'transparent_stepping' attribute takes no arguments}}
7+
void wrong_arg(void) {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang_cc1 %s -verify -fsyntax-only
2+
3+
4+
struct S {
5+
[[clang::transparent_stepping]]
6+
void correct(void) {}
7+
8+
[[clang::transparent_stepping(1)]] // expected-error {{'transparent_stepping' attribute takes no arguments}}
9+
void one_arg(void) {}
10+
};
11+

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

0 commit comments

Comments
 (0)