5757//! ExpectLoadAlignment:{alignment} Checks that the first PT_LOAD segment in the output binary has
5858//! the specified alignment.
5959//!
60+ //! ExpectProgramHeader:{type} Checks that the output binary contains a program header of the
61+ //! specified type.
62+ //!
63+ //! NoProgramHeader:{type} Checks that the output binary contains no program headers of the
64+ //! specified type.
65+ //!
6066//! DoesNotContain:{string} Checks that the output binary doesn't contain the specified string.
6167//!
6268//! Contains:{string} Checks that the output binary does contain the specified string.
@@ -814,6 +820,23 @@ enum DriverMode {
814820 SaveDirResponse ,
815821}
816822
823+ #[ derive( Clone , Copy , Debug , Display , PartialEq , Eq , EnumString ) ]
824+ #[ strum( serialize_all = "SCREAMING_SNAKE_CASE" ) ]
825+ #[ repr( u32 ) ]
826+ enum ProgramHeaderType {
827+ Dynamic = object:: elf:: PT_DYNAMIC ,
828+ Interp = object:: elf:: PT_INTERP ,
829+ GnuEhFrame = object:: elf:: PT_GNU_EH_FRAME ,
830+ GnuProperty = object:: elf:: PT_GNU_PROPERTY ,
831+ GnuRelro = object:: elf:: PT_GNU_RELRO ,
832+ GnuStack = object:: elf:: PT_GNU_STACK ,
833+ Load = object:: elf:: PT_LOAD ,
834+ Note = object:: elf:: PT_NOTE ,
835+ Null = object:: elf:: PT_NULL ,
836+ Phdr = object:: elf:: PT_PHDR ,
837+ Tls = object:: elf:: PT_TLS ,
838+ }
839+
817840#[ derive( Debug , Clone ) ]
818841struct ErrorMatcher {
819842 regex : regex:: Regex ,
@@ -1140,6 +1163,8 @@ struct Assertions {
11401163 expected_section_bytes : Vec < ExpectedSectionBytes > ,
11411164 output_file_matches : Vec < OutputFileMatch > ,
11421165 max_thunks : u64 ,
1166+ expected_program_headers : Vec < ProgramHeaderType > ,
1167+ absent_program_headers : Vec < ProgramHeaderType > ,
11431168}
11441169
11451170#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -1498,6 +1523,18 @@ fn process_directive(
14981523 } ;
14991524 config. assertions . expected_load_alignment = Some ( alignment) ;
15001525 }
1526+ "ExpectProgramHeader" => {
1527+ let header_type: ProgramHeaderType = arg
1528+ . parse ( )
1529+ . with_context ( || format ! ( "Invalid program header type `{arg}`" ) ) ?;
1530+ config. assertions . expected_program_headers . push ( header_type) ;
1531+ }
1532+ "NoProgramHeader" => {
1533+ let header_type: ProgramHeaderType = arg
1534+ . parse ( )
1535+ . with_context ( || format ! ( "Invalid program header type `{arg}`" ) ) ?;
1536+ config. assertions . absent_program_headers . push ( header_type) ;
1537+ }
15011538 "Mode" => {
15021539 let mode: Mode = arg
15031540 . parse ( )
@@ -3430,6 +3467,7 @@ impl Assertions {
34303467 self . verify_dynamic_entries ( & elf_obj) ?;
34313468 self . verify_symbols_absent ( & self . no_sym , elf_obj. dynamic_symbols ( ) , "dynsym" ) ?;
34323469 self . verify_symbols_absent ( & self . no_dynsym , elf_obj. dynamic_symbols ( ) , "dynsym" ) ?;
3470+ self . verify_program_headers ( & elf_obj) ?;
34333471 }
34343472 object:: File :: MachO64 ( _) => {
34353473 if !self . expected_comments . is_empty ( ) {
@@ -3447,6 +3485,12 @@ impl Assertions {
34473485 if !self . absent_dynamic_entries . is_empty ( ) {
34483486 bail ! ( "NoDynamic is not supported for MachO" , ) ;
34493487 }
3488+ if !self . expected_program_headers . is_empty ( ) {
3489+ bail ! ( "ExpectProgramHeader is not supported for MachO" , ) ;
3490+ }
3491+ if !self . absent_program_headers . is_empty ( ) {
3492+ bail ! ( "NoProgramHeader is not supported for MachO" ) ;
3493+ }
34503494 }
34513495 _ => bail ! ( "Unsupported object file format" ) ,
34523496 }
@@ -3676,6 +3720,36 @@ impl Assertions {
36763720 Ok ( ( ) )
36773721 }
36783722
3723+ fn verify_program_headers < ' data > (
3724+ & self ,
3725+ obj : & object:: read:: elf:: ElfFile64 < ' data , object:: Endianness > ,
3726+ ) -> Result {
3727+ if self . expected_program_headers . is_empty ( ) && self . absent_program_headers . is_empty ( ) {
3728+ return Ok ( ( ) ) ;
3729+ }
3730+
3731+ let endian = obj. endian ( ) ;
3732+ let mut header_types = HashSet :: new ( ) ;
3733+
3734+ for header in obj. elf_program_headers ( ) {
3735+ header_types. insert ( header. p_type ( endian) ) ;
3736+ }
3737+
3738+ for header in & self . expected_program_headers {
3739+ if !header_types. contains ( & ( * header as u32 ) ) {
3740+ bail ! ( "Expected program header `{header}' not found." ) ;
3741+ }
3742+ }
3743+
3744+ for header in & self . absent_program_headers {
3745+ if header_types. contains ( & ( * header as u32 ) ) {
3746+ bail ! ( "Program header `{header}' should be absent but was found." ) ;
3747+ }
3748+ }
3749+
3750+ Ok ( ( ) )
3751+ }
3752+
36793753 /// Returns whether we have assertions configured that require metrics to be enabled. Even if
36803754 /// this returns false, if diffing is enabled, we'll collect metrics and check them.
36813755 fn requires_metrics ( & self ) -> bool {
0 commit comments