Debug info: Support variadic functions.

Variadic functions have an unspecified parameter tag after the last
argument. In IR this is represented as an unspecified parameter in the
subroutine type.

Paired commit with CFE r202185.

rdar://problem/13690847

This re-applies r202184 + a bugfix in DwarfDebug's argument handling.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202188 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Adrian Prantl 2014-02-25 19:57:42 +00:00
parent 9791b3f9ae
commit dbaa6ab8b5
5 changed files with 141 additions and 29 deletions

View File

@ -442,7 +442,7 @@ namespace llvm {
/// through debug info anchors. /// through debug info anchors.
void retainType(DIType T); void retainType(DIType T);
/// createUnspecifiedParameter - Create unspeicified type descriptor /// createUnspecifiedParameter - Create unspecified type descriptor
/// for a subroutine type. /// for a subroutine type.
DIDescriptor createUnspecifiedParameter(); DIDescriptor createUnspecifiedParameter();

View File

@ -403,16 +403,22 @@ DIE *DwarfDebug::updateSubprogramScopeDIE(DwarfCompileUnit *SPCU,
DIArray Args = SPTy.getTypeArray(); DIArray Args = SPTy.getTypeArray();
uint16_t SPTag = SPTy.getTag(); uint16_t SPTag = SPTy.getTag();
if (SPTag == dwarf::DW_TAG_subroutine_type) if (SPTag == dwarf::DW_TAG_subroutine_type)
// FIXME: Use DwarfUnit::constructSubprogramArguments() here.
for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) { for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) {
DIType ATy(Args.getElement(i));
if (ATy.isUnspecifiedParameter()) {
assert(i == N-1 && "ellipsis must be the last argument");
SPCU->createAndAddDIE(dwarf::DW_TAG_unspecified_parameters, *SPDie);
} else {
DIE *Arg = DIE *Arg =
SPCU->createAndAddDIE(dwarf::DW_TAG_formal_parameter, *SPDie); SPCU->createAndAddDIE(dwarf::DW_TAG_formal_parameter, *SPDie);
DIType ATy(Args.getElement(i));
SPCU->addType(Arg, ATy); SPCU->addType(Arg, ATy);
if (ATy.isArtificial()) if (ATy.isArtificial())
SPCU->addFlag(Arg, dwarf::DW_AT_artificial); SPCU->addFlag(Arg, dwarf::DW_AT_artificial);
if (ATy.isObjectPointer()) if (ATy.isObjectPointer())
SPCU->addDIEEntry(SPDie, dwarf::DW_AT_object_pointer, Arg); SPCU->addDIEEntry(SPDie, dwarf::DW_AT_object_pointer, Arg);
} }
}
DIE *SPDeclDie = SPDie; DIE *SPDeclDie = SPDie;
SPDie = SPCU->createAndAddDIE(dwarf::DW_TAG_subprogram, SPDie = SPCU->createAndAddDIE(dwarf::DW_TAG_subprogram,
*SPCU->getUnitDie()); *SPCU->getUnitDie());
@ -582,7 +588,7 @@ DIE *DwarfDebug::createScopeChildrenDIE(DwarfCompileUnit *TheCU,
DIE *ObjectPointer = NULL; DIE *ObjectPointer = NULL;
// Collect arguments for current function. // Collect arguments for current function.
if (LScopes.isCurrentFunctionScope(Scope)) if (LScopes.isCurrentFunctionScope(Scope)) {
for (unsigned i = 0, N = CurrentFnArguments.size(); i < N; ++i) for (unsigned i = 0, N = CurrentFnArguments.size(); i < N; ++i)
if (DbgVariable *ArgDV = CurrentFnArguments[i]) if (DbgVariable *ArgDV = CurrentFnArguments[i])
if (DIE *Arg = if (DIE *Arg =
@ -592,6 +598,16 @@ DIE *DwarfDebug::createScopeChildrenDIE(DwarfCompileUnit *TheCU,
ObjectPointer = Arg; ObjectPointer = Arg;
} }
// Create the unspecified parameter that marks a function as variadic.
DISubprogram SP(Scope->getScopeNode());
assert(SP.Verify());
DIArray FnArgs = SP.getType().getTypeArray();
if (FnArgs.getElement(FnArgs.getNumElements()-1).isUnspecifiedParameter()) {
DIE *Ellipsis = new DIE(dwarf::DW_TAG_unspecified_parameters);
Children.push_back(Ellipsis);
}
}
// Collect lexical scope children first. // Collect lexical scope children first.
const SmallVectorImpl<DbgVariable *> &Variables = const SmallVectorImpl<DbgVariable *> &Variables =
ScopeVariables.lookup(Scope); ScopeVariables.lookup(Scope);

View File

@ -1139,6 +1139,22 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, DIDerivedType DTy) {
addSourceLine(&Buffer, DTy); addSourceLine(&Buffer, DTy);
} }
/// constructSubprogramArguments - Construct function argument DIEs.
void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DIArray Args) {
for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) {
DIDescriptor Ty = Args.getElement(i);
if (Ty.isUnspecifiedParameter()) {
assert(i == N-1 && "ellipsis must be the last argument");
createAndAddDIE(dwarf::DW_TAG_unspecified_parameters, Buffer);
} else {
DIE *Arg = createAndAddDIE(dwarf::DW_TAG_formal_parameter, Buffer);
addType(Arg, DIType(Ty));
if (DIType(Ty).isArtificial())
addFlag(Arg, dwarf::DW_AT_artificial);
}
}
}
/// constructTypeDIE - Construct type DIE from DICompositeType. /// constructTypeDIE - Construct type DIE from DICompositeType.
void DwarfUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { void DwarfUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) {
// Add name if not anonymous or intermediate type. // Add name if not anonymous or intermediate type.
@ -1162,19 +1178,12 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) {
addType(&Buffer, RTy); addType(&Buffer, RTy);
bool isPrototyped = true; bool isPrototyped = true;
// Add arguments. if (Elements.getNumElements() == 2 &&
for (unsigned i = 1, N = Elements.getNumElements(); i < N; ++i) { Elements.getElement(1).isUnspecifiedParameter())
DIDescriptor Ty = Elements.getElement(i);
if (Ty.isUnspecifiedParameter()) {
createAndAddDIE(dwarf::DW_TAG_unspecified_parameters, Buffer);
isPrototyped = false; isPrototyped = false;
} else {
DIE *Arg = createAndAddDIE(dwarf::DW_TAG_formal_parameter, Buffer); constructSubprogramArguments(Buffer, Elements);
addType(Arg, DIType(Ty));
if (DIType(Ty).isArtificial())
addFlag(Arg, dwarf::DW_AT_artificial);
}
}
// Add prototype flag if we're dealing with a C language and the // Add prototype flag if we're dealing with a C language and the
// function has been prototyped. // function has been prototyped.
uint16_t Language = getLanguage(); uint16_t Language = getLanguage();
@ -1457,13 +1466,7 @@ DIE *DwarfUnit::getOrCreateSubprogramDIE(DISubprogram SP) {
// Add arguments. Do not add arguments for subprogram definition. They will // Add arguments. Do not add arguments for subprogram definition. They will
// be handled while processing variables. // be handled while processing variables.
for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) { constructSubprogramArguments(*SPDie, Args);
DIE *Arg = createAndAddDIE(dwarf::DW_TAG_formal_parameter, *SPDie);
DIType ATy(Args.getElement(i));
addType(Arg, ATy);
if (ATy.isArtificial())
addFlag(Arg, dwarf::DW_AT_artificial);
}
} }
if (SP.isArtificial()) if (SP.isArtificial())

View File

@ -476,6 +476,9 @@ protected:
DIE *getOrCreateStaticMemberDIE(DIDerivedType DT); DIE *getOrCreateStaticMemberDIE(DIDerivedType DT);
private: private:
/// constructSubprogramArguments - Construct function argument DIEs.
void constructSubprogramArguments(DIE &Buffer, DIArray Args);
/// constructTypeDIE - Construct basic type die from DIBasicType. /// constructTypeDIE - Construct basic type die from DIBasicType.
void constructTypeDIE(DIE &Buffer, DIBasicType BTy); void constructTypeDIE(DIE &Buffer, DIBasicType BTy);

View File

@ -0,0 +1,90 @@
; RUN: llc -O0 -filetype=obj -o %t.o %s
; RUN: llvm-dwarfdump -debug-dump=info %t.o | FileCheck %s
;
; Normal variadic function.
;
; CHECK: DW_TAG_subprogram
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_formal_parameter
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_unspecified_parameters
;
; Variadic C++ member function.
;
; CHECK: DW_TAG_subprogram
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_formal_parameter
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_formal_parameter
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_unspecified_parameters
;
; Variadic function pointer.
;
; CHECK: DW_TAG_subroutine_type
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_formal_parameter
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_unspecified_parameters
;
; Test debug info for variadic function arguments.
; Created from tools/clang/tests/CodeGenCXX/debug-info-varargs.cpp
;
; ModuleID = 'llvm/tools/clang/test/CodeGenCXX/debug-info-varargs.cpp'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.9.0"
%struct.A = type { i8 }
; Function Attrs: nounwind ssp uwtable
define void @_Z1biz(i32 %c, ...) #0 {
%1 = alloca i32, align 4
%a = alloca %struct.A, align 1
%fptr = alloca void (i32, ...)*, align 8
store i32 %c, i32* %1, align 4
call void @llvm.dbg.declare(metadata !{i32* %1}, metadata !21), !dbg !22
call void @llvm.dbg.declare(metadata !{%struct.A* %a}, metadata !23), !dbg !24
call void @llvm.dbg.declare(metadata !{void (i32, ...)** %fptr}, metadata !25), !dbg !27
store void (i32, ...)* @_Z1biz, void (i32, ...)** %fptr, align 8, !dbg !27
ret void, !dbg !28
}
; Function Attrs: nounwind readnone
declare void @llvm.dbg.declare(metadata, metadata) #1
attributes #0 = { nounwind ssp uwtable }
attributes #1 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!18, !19}
!llvm.ident = !{!20}
!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !3, metadata !13, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [llvm/tools/clang/test/CodeGenCXX/debug-info-varargs.cpp] [DW_LANG_C_plus_plus]
!1 = metadata !{metadata !"llvm/tools/clang/test/CodeGenCXX/debug-info-varargs.cpp", metadata !"radar/13690847"}
!2 = metadata !{}
!3 = metadata !{metadata !4}
!4 = metadata !{i32 786451, metadata !1, null, metadata !"A", i32 3, i64 8, i64 8, i32 0, i32 0, null, metadata !5, i32 0, null, null, metadata !"_ZTS1A"} ; [ DW_TAG_structure_type ] [A] [line 3, size 8, align 8, offset 0] [def] [from ]
!5 = metadata !{metadata !6}
!6 = metadata !{i32 786478, metadata !1, metadata !"_ZTS1A", metadata !"a", metadata !"a", metadata !"_ZN1A1aEiz", i32 6, metadata !7, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !12, i32 6} ; [ DW_TAG_subprogram ] [line 6] [a]
!7 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!8 = metadata !{null, metadata !9, metadata !10, metadata !11}
!9 = metadata !{i32 786447, null, null, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 1088, metadata !"_ZTS1A"} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS1A]
!10 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
!11 = metadata !{i32 786456}
!12 = metadata !{i32 786468}
!13 = metadata !{metadata !14}
!14 = metadata !{i32 786478, metadata !1, metadata !15, metadata !"b", metadata !"b", metadata !"_Z1biz", i32 13, metadata !16, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void (i32, ...)* @_Z1biz, null, null, metadata !2, i32 13} ; [ DW_TAG_subprogram ] [line 13] [def] [b]
!15 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [llvm/tools/clang/test/CodeGenCXX/debug-info-varargs.cpp]
!16 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !17, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!17 = metadata !{null, metadata !10, metadata !11}
!18 = metadata !{i32 2, metadata !"Dwarf Version", i32 2}
!19 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
!20 = metadata !{metadata !"clang version 3.5 "}
!21 = metadata !{i32 786689, metadata !14, metadata !"c", metadata !15, i32 16777229, metadata !10, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [c] [line 13]
!22 = metadata !{i32 13, i32 0, metadata !14, null}
!23 = metadata !{i32 786688, metadata !14, metadata !"a", metadata !15, i32 16, metadata !4, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [a] [line 16]
!24 = metadata !{i32 16, i32 0, metadata !14, null}
!25 = metadata !{i32 786688, metadata !14, metadata !"fptr", metadata !15, i32 18, metadata !26, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [fptr] [line 18]
!26 = metadata !{i32 786447, null, null, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 0, metadata !16} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
!27 = metadata !{i32 18, i32 0, metadata !14, null}
!28 = metadata !{i32 22, i32 0, metadata !14, null}