@@ -900,14 +900,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
900900        } 
901901    } 
902902
903-     fn  linux_solarish_readdir64 ( 
904-         & mut  self , 
905-         dirent_type :  & str , 
906-         dirp_op :  & OpTy < ' tcx > , 
907-     )  -> InterpResult < ' tcx ,  Scalar >  { 
903+     fn  readdir64 ( & mut  self ,  dirent_type :  & str ,  dirp_op :  & OpTy < ' tcx > )  -> InterpResult < ' tcx ,  Scalar >  { 
908904        let  this = self . eval_context_mut ( ) ; 
909905
910-         if  !matches ! ( & * this. tcx. sess. target. os,  "linux"  | "solaris"  | "illumos" )  { 
906+         if  !matches ! ( & * this. tcx. sess. target. os,  "linux"  | "solaris"  | "illumos"  |  "freebsd" )  { 
911907            panic ! ( "`linux_solaris_readdir64` should not be called on {}" ,  this. tcx. sess. target. os) ; 
912908        } 
913909
@@ -926,6 +922,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
926922
927923        let  entry = match  open_dir. read_dir . next ( )  { 
928924            Some ( Ok ( dir_entry) )  => { 
925+                 // If the host is a Unix system, fill in the inode number with its real value. 
926+                 // If not, use 0 as a fallback value. 
927+                 #[ cfg( unix) ]  
928+                 let  ino = std:: os:: unix:: fs:: DirEntryExt :: ino ( & dir_entry) ; 
929+                 #[ cfg( not( unix) ) ]  
930+                 let  ino = 0u64 ; 
931+ 
929932                // Write the directory entry into a newly allocated buffer. 
930933                // The name is written with write_bytes, while the rest of the 
931934                // dirent64 (or dirent) struct is written using write_int_fields. 
@@ -947,6 +950,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
947950                //     pub d_reclen: c_ushort, 
948951                //     pub d_name: [c_char; 3], 
949952                // } 
953+                 // 
954+                 // On FreeBSD: 
955+                 // pub struct dirent{ 
956+                 //     pub d_fileno: uint32_t, 
957+                 //     pub d_reclen: uint16_t, 
958+                 //     pub d_type: uint8_t, 
959+                 //     pub d_namlen: uint8_t, 
960+                 //     pub d_name: [c_char; 256] 
961+                 // } 
950962
951963                let  mut  name = dir_entry. file_name ( ) ;  // not a Path as there are no separators! 
952964                name. push ( "\0 " ) ;  // Add a NUL terminator 
@@ -965,31 +977,35 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
965977                    MiriMemoryKind :: Runtime . into ( ) , 
966978                    AllocInit :: Uninit , 
967979                ) ?; 
968-                 let  entry:   Pointer  =  entry. into ( ) ; 
980+                 let  entry = this . ptr_to_mplace ( entry. into ( ) ,  dirent_layout ) ; 
969981
970-                 // If the host is a Unix system, fill in the inode number with its real value. 
971-                 // If not, use 0 as a fallback value. 
972-                 #[ cfg( unix) ]  
973-                 let  ino = std:: os:: unix:: fs:: DirEntryExt :: ino ( & dir_entry) ; 
974-                 #[ cfg( not( unix) ) ]  
975-                 let  ino = 0u64 ; 
976- 
977-                 let  file_type = this. file_type_to_d_type ( dir_entry. file_type ( ) ) ?; 
982+                 // Write common fields 
983+                 let  ino_name =
984+                     if  this. tcx . sess . target . os  == "freebsd"  {  "d_fileno"  }  else  {  "d_ino"  } ; 
978985                this. write_int_fields_named ( 
979-                     & [ ( "d_ino" ,  ino. into ( ) ) ,   ( "d_off" ,   0 ) ,  ( "d_reclen" ,  size. into ( ) ) ] , 
980-                     & this . ptr_to_mplace ( entry,  dirent_layout ) , 
986+                     & [ ( ino_name ,  ino. into ( ) ) ,  ( "d_reclen" ,  size. into ( ) ) ] , 
987+                     & entry, 
981988                ) ?; 
982989
983-                 if  let  Some ( d_type)  = this
984-                     . try_project_field_named ( & this. ptr_to_mplace ( entry,  dirent_layout) ,  "d_type" ) ?
985-                 { 
990+                 // Write "optional" fields. 
991+                 if  let  Some ( d_off)  = this. try_project_field_named ( & entry,  "d_off" ) ? { 
992+                     this. write_null ( & d_off) ?; 
993+                 } 
994+ 
995+                 if  let  Some ( d_namlen)  = this. try_project_field_named ( & entry,  "d_namlen" ) ? { 
996+                     this. write_int ( name_len. strict_sub ( 1 ) ,  & d_namlen) ?; 
997+                 } 
998+ 
999+                 let  file_type = this. file_type_to_d_type ( dir_entry. file_type ( ) ) ?; 
1000+                 if  let  Some ( d_type)  = this. try_project_field_named ( & entry,  "d_type" ) ? { 
9861001                    this. write_int ( file_type,  & d_type) ?; 
9871002                } 
9881003
989-                 let  name_ptr = entry. wrapping_offset ( Size :: from_bytes ( d_name_offset) ,  this) ; 
1004+                 // The name is not a normal field, we already computed the offset above. 
1005+                 let  name_ptr = entry. ptr ( ) . wrapping_offset ( Size :: from_bytes ( d_name_offset) ,  this) ; 
9901006                this. write_bytes_ptr ( name_ptr,  name_bytes. iter ( ) . copied ( ) ) ?; 
9911007
992-                 Some ( entry) 
1008+                 Some ( entry. ptr ( ) ) 
9931009            } 
9941010            None  => { 
9951011                // end of stream: return NULL 
0 commit comments