Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ Attribute Changes in Clang

- Fix a bug where clang doesn't automatically apply the ``[[gsl::Owner]]`` or
``[[gsl::Pointer]]`` to STL explicit template specialization decls. (#GH109442)
- Introduced a new function attribute ``__attribute__((debug_transparent))``
which is intended as a hint to debuggers that they should not stop at the annotated
function, but instead step through it when stepping in, and continuing directly to
its caller when stepping out.

Improvements to Clang's diagnostics
-----------------------------------
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,13 @@ def Artificial : InheritableAttr {
let SimpleHandler = 1;
}

def DebugTransparent: InheritableAttr {
let Spellings = [Clang<"debug_transparent">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let Documentation = [DebugTransparentDocs];
let SimpleHandler = 1;
}

def XRayInstrument : InheritableAttr {
let Spellings = [Clang<"xray_always_instrument">,
Clang<"xray_never_instrument">];
Expand Down
60 changes: 60 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -7866,6 +7866,66 @@ As such, this function attribute is currently only supported on X86 targets.
}];
}

def DebugTransparentDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``debug_transparent`` attribute is intended as a hint for debuggers that this
function itself is not interesting, but it calls a function that might be. So, when
stepping in arrives at a function with this attribute, debuggers should transparently
step-in through it into the functions called by the annotated function (but not by
subsequent calls made by those functions), stopping at the first one its normal rules
for whether to stop says to stop at - or stepping out again if none qualify. Also, when
stepping out arrives at a function with this attribute, the debugger should continue
stepping out to its caller. This attribute is currently only supported by DWARF.

For example:

.. code-block:: c

int bar(void) {
return 42;
}

__attribute__((debug_transparent))
int foo(void) {
return bar();
}

int caller(void) {
return foo();
}

Stepping into ``foo`` should step directly into ``bar`` instead, and stepping out of ``bar``
should stop in ``caller``.

Functions with the ``debug_transparent`` attribute can be chained together:

.. code-block:: c

int baz(void) {
return 42;
}

__attribute__((debug_transparent))
int bar(void) {
return baz();
}

__attribute__((debug_transparent))
int foo(void) {
return bar();
}

int caller(void) {
return foo();
}

In this example, stepping into ``foo`` should step directly into ``baz``, and stepping out of
``baz`` should stop in ``caller``.
}];
}


def ReadOnlyPlacementDocs : Documentation {
let Category = DocCatType;
let Content = [{This attribute is attached to a structure, class or union declaration.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -467,4 +467,6 @@ def warn_try_not_valid_on_target : Warning<
"target '%0' does not support exception handling;"
" 'catch' block is ignored">,
InGroup<OpenMPTargetException>;
def warn_debug_transparent_ignored : Warning<
"'debug_transparent' attribute is ignored since it is only supported by DWARF">;
}
17 changes: 17 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Attrs.inc"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
Expand Down Expand Up @@ -109,6 +110,20 @@ static bool IsArtificial(VarDecl const *VD) {
cast<Decl>(VD->getDeclContext())->isImplicit());
}

static bool usesDebugTransparent(const Decl *D, const CodeGenModule &CGM) {
if (!D)
return false;

if (auto *attr = D->getAttr<DebugTransparentAttr>()) {
if (CGM.getCodeGenOpts().DwarfVersion == 0)
CGM.getDiags().Report(attr->getLocation(),
diag::warn_debug_transparent_ignored);
return true;
}

return false;
}

CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
: CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
Expand Down Expand Up @@ -4480,6 +4495,8 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc,
SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
if (usesDebugTransparent(D, CGM))
SPFlags |= llvm::DISubprogram::SPFlagIsDebugTransparent;

llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs();
llvm::DISubprogram::DISPFlags SPFlagsForDef =
Expand Down
37 changes: 37 additions & 0 deletions clang/test/CodeGen/attr-debug-transparent-cxx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// RUN: %clang -gdwarf -emit-llvm -S %s -o - | FileCheck %s

void foo(void) {}

struct A {
[[clang::debug_transparent()]]
A() {
foo();
}

[[clang::debug_transparent()]]
~A() {
foo();
}
[[clang::debug_transparent()]]
void method(void) {
foo();
}

[[clang::always_inline()]]
[[clang::debug_transparent()]]
void inline_method(void) {
foo();
}

};

int main() {
auto a = A();
a.method();
a.inline_method();
}

// CHECK: DISubprogram(name: "inline_method"{{.*}} DISPFlagIsDebugTransparent
// CHECK: DISubprogram(name: "method"{{.*}} DISPFlagIsDebugTransparent
// CHECK: DISubprogram(name: "A"{{.*}} DISPFlagIsDebugTransparent
// CHECK: DISubprogram(name: "~A"{{.*}} DISPFlagIsDebugTransparent
14 changes: 14 additions & 0 deletions clang/test/CodeGen/attr-debug-transparent-method-warning.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Pipe stderr to FileCheck since we're checking for a warning
// RUN: %clang -gcodeview -g -emit-llvm -S %s -o - 2>&1 | FileCheck %s


struct S {
[[clang::debug_transparent]]
void foo(void) {}
};

int main() {
S s;
s.foo();
}
// CHECK: warning: 'debug_transparent' attribute is ignored since it is only supported by DWARF
10 changes: 10 additions & 0 deletions clang/test/CodeGen/attr-debug-transparent-no-warning.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Pipe stderr to FileCheck since we're checking for a warning
// RUN: %clang -gcodeview -emit-llvm -S %s -o - 2>&1 | FileCheck %s


__attribute__((debug_transparent))
void foo(void) {}

// Check that the warning is NOT printed when compiling without debug information.
// CHECK-NOT: warning: 'debug_transparent' attribute is ignored since it is only supported by DWARF

12 changes: 12 additions & 0 deletions clang/test/CodeGen/attr-debug-transparent-objc-warning.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Pipe stderr to FileCheck since we're checking for a warning
// RUN: %clang -gcodeview -g -emit-llvm -S %s -o - 2>&1 | FileCheck %s

@interface ObjCClass
- (void)foo __attribute__((debug_transparent));
@end

@implementation ObjCClass
- (void)foo {}
@end

// CHECK: warning: 'debug_transparent' attribute is ignored since it is only supported by DWARF
13 changes: 13 additions & 0 deletions clang/test/CodeGen/attr-debug-transparent-objc.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang -gdwarf -emit-llvm -S %s -o - | FileCheck %s


@interface ObjCClass
- (void)foo __attribute__((debug_transparent));
@end

@implementation ObjCClass
- (void)foo {}
@end


// CHECK: DISubprogram(name: "-[ObjCClass foo]"{{.*}} DISPFlagIsDebugTransparent
9 changes: 9 additions & 0 deletions clang/test/CodeGen/attr-debug-transparent-warning.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Pipe stderr to FileCheck since we're checking for a warning
// RUN: %clang -gcodeview -g -emit-llvm -S %s -o - 2>&1 | FileCheck %s


__attribute__((debug_transparent))
void foo(void) {}

// CHECK: warning: 'debug_transparent' attribute is ignored since it is only supported by DWARF

10 changes: 10 additions & 0 deletions clang/test/CodeGen/attr-debug-transparent.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang -gdwarf -emit-llvm -S %s -o - | FileCheck %s

void bar(void) {}

__attribute__((debug_transparent))
void foo(void) {
bar();
}

// CHECK: DISubprogram(name: "foo"{{.*}} DISPFlagIsDebugTransparent
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
// CHECK-NEXT: CoroWrapper (SubjectMatchRule_function)
// CHECK-NEXT: DLLExport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
// CHECK-NEXT: DLLImport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
// CHECK-NEXT: DebugTransparent (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: Destructor (SubjectMatchRule_function)
// CHECK-NEXT: DiagnoseAsBuiltin (SubjectMatchRule_function)
// CHECK-NEXT: DisableSanitizerInstrumentation (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
Expand Down
7 changes: 7 additions & 0 deletions clang/test/Sema/attr-debug-transparent.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only

__attribute__((debug_transparent))
void correct(void) {}

__attribute__((debug_transparent(1))) // expected-error {{'debug_transparent' attribute takes no arguments}}
void wrong_arg(void) {}
11 changes: 11 additions & 0 deletions clang/test/SemaCXX/attr-debug-transparent-method.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only


struct S {
[[clang::debug_transparent]]
void correct(void) {}

[[clang::debug_transparent(1)]] // expected-error {{'debug_transparent' attribute takes no arguments}}
void one_arg(void) {}
};

9 changes: 9 additions & 0 deletions clang/test/SemaObjC/attr-debug-transparent-objc.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only



@interface ObjCClass
- (void)correct __attribute__((debug_transparent));
- (void)one_arg __attribute__((debug_transparent(1))); // expected-error {{'debug_transparent' attribute takes no arguments}}
@end

3 changes: 2 additions & 1 deletion llvm/include/llvm/IR/DebugInfoFlags.def
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,12 @@ HANDLE_DISP_FLAG((1u << 8), MainSubprogram)
// for defaulted functions
HANDLE_DISP_FLAG((1u << 9), Deleted)
HANDLE_DISP_FLAG((1u << 11), ObjCDirect)
HANDLE_DISP_FLAG((1u << 12), IsDebugTransparent)

#ifdef DISP_FLAG_LARGEST_NEEDED
// Intended to be used with ADT/BitmaskEnum.h.
// NOTE: Always must be equal to largest flag, check this when adding new flags.
HANDLE_DISP_FLAG((1 << 11), Largest)
HANDLE_DISP_FLAG((1 << 12), Largest)
#undef DISP_FLAG_LARGEST_NEEDED
#endif

Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,9 @@ class DISubprogram : public DILocalScope {
bool isElemental() const { return getSPFlags() & SPFlagElemental; }
bool isRecursive() const { return getSPFlags() & SPFlagRecursive; }
bool isObjCDirect() const { return getSPFlags() & SPFlagObjCDirect; }
bool isDebugTransparent() const {
return getSPFlags() & SPFlagIsDebugTransparent;
}

/// Check if this is deleted member function.
///
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,9 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP,
(DD->useAllLinkageNames() || DU->getAbstractScopeDIEs().lookup(SP)))
addLinkageName(SPDie, LinkageName);

if (SP->isDebugTransparent())
addFlag(SPDie, dwarf::DW_AT_trampoline);

if (!DeclDie)
return false;

Expand Down Expand Up @@ -1378,6 +1381,8 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie,

if (!SP->getTargetFuncName().empty())
addString(SPDie, dwarf::DW_AT_trampoline, SP->getTargetFuncName());
else if (SP->isDebugTransparent())
addFlag(SPDie, dwarf::DW_AT_trampoline);

if (DD->getDwarfVersion() >= 5 && SP->isDeleted())
addFlag(SPDie, dwarf::DW_AT_deleted);
Expand Down
39 changes: 39 additions & 0 deletions llvm/test/Assembler/disubprogram-debug-transparent.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; This test verifies that the DISPFlagIsDebugTransparent attribute in a DISubprogram
; is assembled/disassembled correctly.
;
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
;
; CHECK: !DISubprogram(name: "baz",{{.*}} DISPFlagIsDebugTransparent
;
; ModuleID = 't.c'
source_filename = "t.c"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx13.0.0"

; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
define void @baz() #0 !dbg !10 {
entry:
ret void, !dbg !14
}

attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}
!llvm.dbg.cu = !{!7}
!llvm.ident = !{!9}

!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 2]}
!1 = !{i32 7, !"Dwarf Version", i32 4}
!2 = !{i32 2, !"Debug Info Version", i32 3}
!3 = !{i32 1, !"wchar_size", i32 4}
!4 = !{i32 8, !"PIC Level", i32 2}
!5 = !{i32 7, !"uwtable", i32 1}
!6 = !{i32 7, !"frame-pointer", i32 1}
!7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !8, producer: "clang version 17.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!8 = !DIFile(filename: "t.c", directory: "/")
!9 = !{!"clang version 17.0.0"}
!10 = distinct !DISubprogram(name: "baz", scope: !8, file: !8, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagIsDebugTransparent, unit: !7, retainedNodes: !13)
!11 = !DISubroutineType(types: !12)
!12 = !{null}
!13 = !{}
!14 = !DILocation(line: 4, column: 1, scope: !10)
Loading
Loading