Skip to content

Commit 8ed84bc

Browse files
committed
[AArch64][PAC][lldb][Dwarf] Support [[clang::ptrauth_vtable_pointer(...)]] attribute
- Encode the attribute in Dwarf as a `DW_TAG_LLVM_ptrauth_type` entry corresponding to vtable pointer. The attribute supports "default" values for address and extra discrimination, but in Dwarf we emit actual values due to `DW_AT_LLVM_ptrauth_*` attributes limitations. See lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp for details. - When parsing dynamic class and structure types from Dwarf, check the vtable pointer type against `DW_TAG_LLVM_ptrauth_type`. If true, apply the `clang::ptrauth_vtable_pointer` attribute with corresponding parameters to the class record decl. "Default" address and extra discrimination values are not restored, the actual ones are, but the result is effectively the same since the signing schema must be preserved unchanged.
1 parent 8e62fa8 commit 8ed84bc

File tree

3 files changed

+358
-0
lines changed

3 files changed

+358
-0
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2432,6 +2432,47 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
24322432
if (!VPtrTy)
24332433
VPtrTy = getOrCreateVTablePtrType(Unit);
24342434

2435+
if (auto *VptrAuthAttr = RD->getAttr<VTablePointerAuthenticationAttr>()) {
2436+
unsigned TypedDiscriminator =
2437+
CGM.getContext().getPointerAuthVTablePointerDiscriminator(RD);
2438+
auto &LangOpts = CGM.getContext().getLangOpts();
2439+
2440+
unsigned Key = VptrAuthAttr->getKey();
2441+
2442+
bool HasAddressDiscrimination =
2443+
LangOpts.PointerAuthVTPtrAddressDiscrimination;
2444+
if (VptrAuthAttr->getAddressDiscrimination() !=
2445+
VTablePointerAuthenticationAttr::DefaultAddressDiscrimination) {
2446+
HasAddressDiscrimination =
2447+
(VptrAuthAttr->getAddressDiscrimination() ==
2448+
VTablePointerAuthenticationAttr::AddressDiscrimination);
2449+
}
2450+
2451+
unsigned ExtraDiscriminator = 0;
2452+
2453+
switch (VptrAuthAttr->getExtraDiscrimination()) {
2454+
case VTablePointerAuthenticationAttr::DefaultExtraDiscrimination:
2455+
if (LangOpts.PointerAuthVTPtrTypeDiscrimination)
2456+
ExtraDiscriminator = TypedDiscriminator;
2457+
break;
2458+
case VTablePointerAuthenticationAttr::TypeDiscrimination:
2459+
ExtraDiscriminator = TypedDiscriminator;
2460+
break;
2461+
case VTablePointerAuthenticationAttr::CustomDiscrimination:
2462+
ExtraDiscriminator = VptrAuthAttr->getCustomDiscriminationValue();
2463+
break;
2464+
case VTablePointerAuthenticationAttr::NoExtraDiscrimination:
2465+
break;
2466+
}
2467+
2468+
// See CodeGenModule::computeVTPointerAuthentication:
2469+
// isIsaPointer and authenticatesNullValues are always false.
2470+
VPtrTy = DBuilder.createPtrAuthQualifiedType(
2471+
VPtrTy, Key, HasAddressDiscrimination, ExtraDiscriminator,
2472+
/* isIsaPointer */ false,
2473+
/* authenticatesNullValues */ false);
2474+
}
2475+
24352476
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
24362477
llvm::DIType *VPtrMember =
24372478
DBuilder.createMemberType(Unit, getVTableName(RD), Unit, 0, Size, 0, 0,

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,6 +1842,48 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
18421842
attrs.name.GetCString(), tag_decl_kind, attrs.class_language,
18431843
&metadata, attrs.exports_symbols);
18441844
}
1845+
1846+
if (metadata.GetIsDynamicCXXType()) {
1847+
clang::RecordDecl *record_decl = m_ast.GetAsRecordDecl(clang_type);
1848+
DWARFDIE vptr_type_die =
1849+
die.GetFirstChild().GetAttributeValueAsReferenceDIE(DW_AT_type);
1850+
if (vptr_type_die.Tag() == DW_TAG_LLVM_ptrauth_type) {
1851+
unsigned key = vptr_type_die.GetAttributeValueAsUnsigned(
1852+
DW_AT_LLVM_ptrauth_key, -1);
1853+
unsigned discriminator = vptr_type_die.GetAttributeValueAsUnsigned(
1854+
DW_AT_LLVM_ptrauth_extra_discriminator, -1);
1855+
unsigned has_addr_discr = vptr_type_die.GetAttributeValueAsUnsigned(
1856+
DW_AT_LLVM_ptrauth_address_discriminated, -1);
1857+
1858+
auto error_missing = [&vptr_type_die](const dw_attr_t attr) {
1859+
vptr_type_die.GetDWARF()->GetObjectFile()->GetModule()->ReportError(
1860+
"[{0:x16}]: missing attribute {1:x4} ({2}) required for signed "
1861+
"vtable pointer",
1862+
vptr_type_die.GetOffset(), attr, DW_AT_value_to_name(attr));
1863+
};
1864+
1865+
if (key == unsigned(-1))
1866+
error_missing(DW_AT_LLVM_ptrauth_key);
1867+
if (discriminator == unsigned(-1))
1868+
error_missing(DW_AT_LLVM_ptrauth_extra_discriminator);
1869+
if (has_addr_discr == unsigned(-1))
1870+
error_missing(DW_AT_LLVM_ptrauth_extra_discriminator);
1871+
1872+
record_decl->addAttr(
1873+
clang::VTablePointerAuthenticationAttr::CreateImplicit(
1874+
m_ast.getASTContext(),
1875+
key == 2
1876+
? clang::VTablePointerAuthenticationAttr::ProcessDependent
1877+
: clang::VTablePointerAuthenticationAttr::
1878+
ProcessIndependent,
1879+
has_addr_discr ? clang::VTablePointerAuthenticationAttr::
1880+
AddressDiscrimination
1881+
: clang::VTablePointerAuthenticationAttr::
1882+
NoAddressDiscrimination,
1883+
clang::VTablePointerAuthenticationAttr::CustomDiscrimination,
1884+
discriminator));
1885+
}
1886+
}
18451887
}
18461888

18471889
// Store a forward declaration to this class type in case any

lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,281 @@ TEST_F(DWARFASTParserClangTests, TestPtrAuthParsing) {
420420
ASSERT_EQ(type_as_string, "void (*__ptrauth(0,0,42))(...)");
421421
}
422422

423+
TEST_F(DWARFASTParserClangTests, TestVTablePtrAuthParsing) {
424+
// Tests parsing dynamic structure types with explicit vtable pointer
425+
// authentication
426+
427+
// This is Dwarf for the following C++ code:
428+
// ```
429+
// struct [[clang::ptrauth_vtable_pointer(process_dependent,
430+
// address_discrimination,
431+
// custom_discrimination, 42)]] A {
432+
// virtual void foo() {}
433+
// };
434+
// A a;
435+
// ```
436+
437+
const char *yamldata = R"(
438+
--- !ELF
439+
FileHeader:
440+
Class: ELFCLASS64
441+
Data: ELFDATA2LSB
442+
Type: ET_EXEC
443+
Machine: EM_AARCH64
444+
DWARF:
445+
debug_str:
446+
- a
447+
- A
448+
- _vptr$A
449+
- foo
450+
- __vtbl_ptr_type
451+
- int
452+
debug_abbrev:
453+
- ID: 0
454+
Table:
455+
- Code: 0x1
456+
Tag: DW_TAG_compile_unit
457+
Children: DW_CHILDREN_yes
458+
Attributes:
459+
- Attribute: DW_AT_language
460+
Form: DW_FORM_data2
461+
- Code: 0x2
462+
Tag: DW_TAG_variable
463+
Children: DW_CHILDREN_no
464+
Attributes:
465+
- Attribute: DW_AT_name
466+
Form: DW_FORM_strp
467+
- Attribute: DW_AT_type
468+
Form: DW_FORM_ref4
469+
- Attribute: DW_AT_external
470+
Form: DW_FORM_flag_present
471+
- Code: 0x3
472+
Tag: DW_TAG_structure_type
473+
Children: DW_CHILDREN_yes
474+
Attributes:
475+
- Attribute: DW_AT_containing_type
476+
Form: DW_FORM_ref4
477+
- Attribute: DW_AT_name
478+
Form: DW_FORM_strp
479+
- Code: 0x4
480+
Tag: DW_TAG_member
481+
Children: DW_CHILDREN_no
482+
Attributes:
483+
- Attribute: DW_AT_name
484+
Form: DW_FORM_strp
485+
- Attribute: DW_AT_type
486+
Form: DW_FORM_ref4
487+
- Attribute: DW_AT_artificial
488+
Form: DW_FORM_flag_present
489+
- Code: 0x5
490+
Tag: DW_TAG_subprogram
491+
Children: DW_CHILDREN_yes
492+
Attributes:
493+
- Attribute: DW_AT_name
494+
Form: DW_FORM_strp
495+
- Attribute: DW_AT_virtuality
496+
Form: DW_FORM_data1
497+
- Attribute: DW_AT_containing_type
498+
Form: DW_FORM_ref4
499+
- Code: 0x6
500+
Tag: DW_TAG_formal_parameter
501+
Children: DW_CHILDREN_no
502+
Attributes:
503+
- Attribute: DW_AT_type
504+
Form: DW_FORM_ref4
505+
- Attribute: DW_AT_artificial
506+
Form: DW_FORM_flag_present
507+
- Code: 0x7
508+
Tag: DW_TAG_LLVM_ptrauth_type
509+
Children: DW_CHILDREN_no
510+
Attributes:
511+
- Attribute: DW_AT_type
512+
Form: DW_FORM_ref4
513+
- Attribute: DW_AT_LLVM_ptrauth_key
514+
Form: DW_FORM_data1
515+
- Attribute: DW_AT_LLVM_ptrauth_extra_discriminator
516+
Form: DW_FORM_data2
517+
- Attribute: DW_AT_LLVM_ptrauth_address_discriminated
518+
Form: DW_FORM_flag_present
519+
- Code: 0x8
520+
Tag: DW_TAG_pointer_type
521+
Children: DW_CHILDREN_no
522+
Attributes:
523+
- Attribute: DW_AT_type
524+
Form: DW_FORM_ref4
525+
- Code: 0x9
526+
Tag: DW_TAG_pointer_type
527+
Children: DW_CHILDREN_no
528+
Attributes:
529+
- Attribute: DW_AT_type
530+
Form: DW_FORM_ref4
531+
- Attribute: DW_AT_name
532+
Form: DW_FORM_strp
533+
- Code: 0xA
534+
Tag: DW_TAG_subroutine_type
535+
Children: DW_CHILDREN_no
536+
Attributes:
537+
- Attribute: DW_AT_type
538+
Form: DW_FORM_ref4
539+
- Code: 0xB
540+
Tag: DW_TAG_base_type
541+
Children: DW_CHILDREN_no
542+
Attributes:
543+
- Attribute: DW_AT_name
544+
Form: DW_FORM_strp
545+
- Attribute: DW_AT_encoding
546+
Form: DW_FORM_data1
547+
- Attribute: DW_AT_byte_size
548+
Form: DW_FORM_data1
549+
- Code: 0xC
550+
Tag: DW_TAG_pointer_type
551+
Children: DW_CHILDREN_no
552+
Attributes:
553+
- Attribute: DW_AT_type
554+
Form: DW_FORM_ref4
555+
556+
debug_info:
557+
- Version: 5
558+
UnitType: DW_UT_compile
559+
AddrSize: 8
560+
Entries:
561+
# 0x0c: DW_TAG_compile_unit
562+
# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus_11)
563+
- AbbrCode: 0x1
564+
Values:
565+
- Value: 0x1A
566+
567+
# 0x0f: DW_TAG_variable
568+
# DW_AT_name [DW_FORM_strp] (\"a\")
569+
# DW_AT_type [DW_FORM_ref4] (0x00000018 \"A\")
570+
# DW_AT_external [DW_FORM_flag_present] (true)
571+
- AbbrCode: 0x2
572+
Values:
573+
- Value: 0x00
574+
- Value: 0x18
575+
576+
# 0x18: DW_TAG_structure_type
577+
# DW_AT_containing_type [DW_FORM_ref4] (0x00000018 \"A\")
578+
# DW_AT_name [DW_FORM_strp] (\"A\")
579+
- AbbrCode: 0x3
580+
Values:
581+
- Value: 0x18
582+
- Value: 0x02
583+
584+
# 0x21: DW_TAG_member
585+
# DW_AT_name [DW_FORM_strp] (\"_vptr$A\")
586+
# DW_AT_type [DW_FORM_ref4] (0x0000002f)
587+
# DW_AT_artificial [DW_FORM_flag_present] (true)
588+
- AbbrCode: 0x4
589+
Values:
590+
- Value: 0x04
591+
- Value: 0x3B
592+
593+
# 0x2a: DW_TAG_subprogram
594+
# DW_AT_name [DW_FORM_strp] (\"foo\")
595+
# DW_AT_virtuality [DW_FORM_data1] (DW_VIRTUALITY_virtual)
596+
# DW_AT_containing_type [DW_FORM_ref4] (0x00000018 \"A\")
597+
- AbbrCode: 0x5
598+
Values:
599+
- Value: 0x0C
600+
- Value: 0x01
601+
- Value: 0x18
602+
603+
# 0x34: DW_TAG_formal_parameter
604+
# DW_AT_type [DW_FORM_ref4] (0x0000005d \"A *\")
605+
# DW_AT_artificial [DW_FORM_flag_present] (true)
606+
- AbbrCode: 0x6
607+
Values:
608+
- Value: 0x5D
609+
610+
- AbbrCode: 0x0 # end of child tags of 0x2a
611+
- AbbrCode: 0x0 # end of child tags of 0x18
612+
613+
# 0x3b: DW_TAG_LLVM_ptrauth_type
614+
# DW_AT_type [DW_FORM_ref4] (0x00000043 \"int (**)()\")
615+
# DW_AT_LLVM_ptrauth_key [DW_FORM_data1] (0x02)
616+
# DW_AT_LLVM_ptrauth_extra_discriminator [DW_FORM_data2] (0x002a)
617+
# DW_AT_LLVM_ptrauth_address_discriminated [DW_FORM_flag_present] (true)
618+
- AbbrCode: 0x7
619+
Values:
620+
- Value: 0x43
621+
- Value: 0x02
622+
- Value: 0x2A
623+
624+
# 0x43: DW_TAG_pointer_type
625+
# DW_AT_type [DW_FORM_ref4] (0x00000048 \"int (*)()\")
626+
- AbbrCode: 0x8
627+
Values:
628+
- Value: 0x48
629+
630+
# 0x48: DW_TAG_pointer_type
631+
# DW_AT_type [DW_FORM_ref4] (0x00000051 \"int ()\")
632+
# DW_AT_name [DW_FORM_strp] (\"__vtbl_ptr_type\")
633+
- AbbrCode: 0x9
634+
Values:
635+
- Value: 0x51
636+
- Value: 0x10
637+
638+
# 0x51: DW_TAG_subroutine_type
639+
# DW_AT_type [DW_FORM_ref4] (0x00000056 \"int\")
640+
- AbbrCode: 0xA
641+
Values:
642+
- Value: 0x56
643+
644+
# 0x56: DW_TAG_base_type
645+
# DW_AT_name [DW_FORM_strp] (\"int\")
646+
# DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed)
647+
# DW_AT_byte_size [DW_FORM_data1] (0x04)
648+
- AbbrCode: 0xB
649+
Values:
650+
- Value: 0x20
651+
- Value: 0x05
652+
- Value: 0x04
653+
654+
# 0x5d: DW_TAG_pointer_type
655+
# DW_AT_type [DW_FORM_ref4] (0x00000018 \"A\")
656+
- AbbrCode: 0xC
657+
Values:
658+
- Value: 0x18
659+
660+
- AbbrCode: 0x0 # end of child tags of 0x0c
661+
...
662+
)";
663+
YAMLModuleTester t(yamldata);
664+
665+
DWARFUnit *unit = t.GetDwarfUnit();
666+
ASSERT_NE(unit, nullptr);
667+
const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
668+
ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
669+
DWARFDIE cu_die(unit, cu_entry);
670+
671+
auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast");
672+
auto &ast_ctx = *holder->GetAST();
673+
DWARFASTParserClangStub ast_parser(ast_ctx);
674+
675+
DWARFDIE struct_object = cu_die.GetFirstChild();
676+
ASSERT_EQ(struct_object.Tag(), DW_TAG_variable);
677+
DWARFDIE structure_type =
678+
struct_object.GetAttributeValueAsReferenceDIE(DW_AT_type);
679+
ASSERT_EQ(structure_type.Tag(), DW_TAG_structure_type);
680+
681+
SymbolContext sc;
682+
bool new_type = false;
683+
lldb::TypeSP type =
684+
ast_parser.ParseTypeFromDWARF(sc, structure_type, &new_type);
685+
clang::RecordDecl *record_decl =
686+
TypeSystemClang::GetAsRecordDecl(type->GetForwardCompilerType());
687+
auto *attr = record_decl->getAttr<clang::VTablePointerAuthenticationAttr>();
688+
ASSERT_NE(attr, nullptr);
689+
ASSERT_EQ(attr->getKey(),
690+
clang::VTablePointerAuthenticationAttr::ProcessDependent);
691+
ASSERT_EQ(attr->getAddressDiscrimination(),
692+
clang::VTablePointerAuthenticationAttr::AddressDiscrimination);
693+
ASSERT_EQ(attr->getExtraDiscrimination(),
694+
clang::VTablePointerAuthenticationAttr::CustomDiscrimination);
695+
ASSERT_EQ(attr->getCustomDiscriminationValue(), 42);
696+
}
697+
423698
struct ExtractIntFromFormValueTest : public testing::Test {
424699
SubsystemRAII<FileSystem, HostInfo> subsystems;
425700
clang_utils::TypeSystemClangHolder holder;

0 commit comments

Comments
 (0)