1use crate::util;
8use thiserror::Error;
9
10#[derive(Error, Debug)]
12pub enum ElfLoadError {
13 #[error("ELF load segments were empty")]
14 NothingToLoad,
15 #[error("Failed to allocate VMAR for ELF: {}", _0)]
16 VmarAllocate(zx::Status),
17 #[error("Failed to map VMAR: {}", _0)]
18 VmarMap(zx::Status),
19 #[error("Failed to create CoW VMO clone: {}", _0)]
20 VmoCowClone(zx::Status),
21 #[error("Failed to create VMO: {}", _0)]
22 VmoCreate(zx::Status),
23 #[error("Failed to read from VMO: {}", _0)]
24 VmoRead(zx::Status),
25 #[error("Failed to write to VMO: {}", _0)]
26 VmoWrite(zx::Status),
27 #[error("Failed to get VMO name: {}", _0)]
28 GetVmoName(zx::Status),
29 #[error("Failed to set VMO name: {}", _0)]
30 SetVmoName(zx::Status),
31}
32
33impl ElfLoadError {
34 pub fn as_zx_status(&self) -> zx::Status {
36 match self {
37 ElfLoadError::NothingToLoad => zx::Status::NOT_FOUND,
38 ElfLoadError::VmarAllocate(s)
39 | ElfLoadError::VmarMap(s)
40 | ElfLoadError::VmoCowClone(s)
41 | ElfLoadError::VmoCreate(s)
42 | ElfLoadError::VmoRead(s)
43 | ElfLoadError::VmoWrite(s)
44 | ElfLoadError::GetVmoName(s)
45 | ElfLoadError::SetVmoName(s) => *s,
46 }
47 }
48}
49
50#[derive(Debug)]
52pub struct LoadedElfInfo {
53 pub low: usize,
55
56 pub high: usize,
58
59 pub max_perm: elf_parse::SegmentFlags,
61}
62
63pub fn loaded_elf_info(headers: &elf_parse::Elf64Headers) -> LoadedElfInfo {
67 let (mut first, mut low, mut high) = (true, 0, 0);
68 let mut max_perm = elf_parse::SegmentFlags::empty();
69 for hdr in headers.program_headers_with_type(elf_parse::SegmentType::Load) {
70 if first {
72 low = util::page_start(hdr.vaddr);
73 first = false;
74 }
75 high = util::page_end(hdr.vaddr + hdr.memsz as usize);
76 max_perm |= hdr.flags();
77 }
78 LoadedElfInfo { low, high, max_perm }
79}
80
81#[derive(Debug)]
83pub struct LoadedElf {
84 pub vmar: zx::Vmar,
86
87 pub vmar_base: usize,
89
90 pub entry: usize,
92}
93
94pub trait Mapper {
96 fn map(
100 &self,
101 vmar_offset: usize,
102 vmo: &zx::Vmo,
103 vmo_offset: u64,
104 length: usize,
105 flags: zx::VmarFlags,
106 ) -> Result<usize, zx::Status>;
107}
108
109impl Mapper for zx::Vmar {
110 fn map(
111 &self,
112 vmar_offset: usize,
113 vmo: &zx::Vmo,
114 vmo_offset: u64,
115 length: usize,
116 flags: zx::VmarFlags,
117 ) -> Result<usize, zx::Status> {
118 Self::map(self, vmar_offset, vmo, vmo_offset, length, flags)
119 }
120}
121
122pub fn load_elf(
124 vmo: &zx::Vmo,
125 headers: &elf_parse::Elf64Headers,
126 root_vmar: &zx::Vmar,
127) -> Result<LoadedElf, ElfLoadError> {
128 let info = loaded_elf_info(headers);
129 let size = info.high - info.low;
130 if size == 0 {
131 return Err(ElfLoadError::NothingToLoad);
132 }
133
134 let flags = zx::VmarFlags::CAN_MAP_SPECIFIC | elf_to_vmar_can_map_flags(&info.max_perm);
137 let (vmar, vmar_base) =
138 root_vmar.allocate(0, size, flags).map_err(|s| ElfLoadError::VmarAllocate(s))?;
139
140 let vaddr_bias = vmar_base.wrapping_sub(info.low);
144
145 map_elf_segments(vmo, headers, &vmar, vmar_base, vaddr_bias)?;
146 Ok(LoadedElf { vmar, vmar_base, entry: headers.file_header().entry.wrapping_add(vaddr_bias) })
147}
148
149pub fn map_elf_segments(
151 vmo: &zx::Vmo,
152 headers: &elf_parse::Elf64Headers,
153 mapper: &dyn Mapper,
154 mapper_base: usize,
155 vaddr_bias: usize,
156) -> Result<(), ElfLoadError> {
157 let mapper_relative_bias = vaddr_bias.wrapping_sub(mapper_base);
167 let vmo_name = vmo.get_name().map_err(|s| ElfLoadError::GetVmoName(s))?;
168 for hdr in headers.program_headers_with_type(elf_parse::SegmentType::Load) {
169 let adjust = util::page_offset(hdr.offset);
171 let mut file_offset = hdr.offset - adjust;
172 let file_size = hdr.filesz + adjust as u64;
173 let virt_offset = hdr.vaddr - adjust;
174 let virt_size = hdr.memsz + adjust as u64;
175
176 let virt_addr = virt_offset.wrapping_add(mapper_relative_bias);
179
180 let must_write = virt_size > file_size && util::page_offset(file_size as usize) != 0;
184
185 let vmo_to_map: &zx::Vmo;
189 let writeable_vmo: zx::Vmo;
190 if must_write || (file_size > 0 && hdr.flags().contains(elf_parse::SegmentFlags::WRITE)) {
191 writeable_vmo = vmo
192 .create_child(
193 zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE,
194 file_offset as u64,
195 util::page_end(file_size as usize) as u64,
196 )
197 .map_err(ElfLoadError::VmoCowClone)?;
198 writeable_vmo
199 .set_name(&vmo_name_with_prefix(&vmo_name, VMO_NAME_PREFIX_DATA))
200 .map_err(ElfLoadError::SetVmoName)?;
201 file_offset = 0;
203
204 if virt_size > file_size {
206 let memset_size = util::page_end(file_size as usize) - file_size as usize;
208 if memset_size > 0 {
209 writeable_vmo
210 .write(&vec![0u8; memset_size], file_size)
211 .map_err(|s| ElfLoadError::VmoWrite(s))?;
212 }
213 }
214 vmo_to_map = &writeable_vmo;
215 } else {
216 vmo_to_map = vmo;
217 }
218
219 let flags = zx::VmarFlags::SPECIFIC
223 | zx::VmarFlags::ALLOW_FAULTS
224 | elf_to_vmar_perm_flags(&hdr.flags());
225 if file_size != 0 {
226 mapper
227 .map(
228 virt_addr,
229 vmo_to_map,
230 file_offset as u64,
231 util::page_end(file_size as usize),
232 flags,
233 )
234 .map_err(ElfLoadError::VmarMap)?;
235 }
236
237 if virt_size > file_size {
241 let bss_vmo_start = util::page_end(file_size as usize);
243 let bss_vmo_size = util::page_end(virt_size as usize) - bss_vmo_start;
244 if bss_vmo_size > 0 {
245 let anon_vmo =
246 zx::Vmo::create(bss_vmo_size as u64).map_err(|s| ElfLoadError::VmoCreate(s))?;
247 anon_vmo
248 .set_name(&vmo_name_with_prefix(&vmo_name, VMO_NAME_PREFIX_BSS))
249 .map_err(ElfLoadError::SetVmoName)?;
250 mapper
251 .map(virt_addr + bss_vmo_start, &anon_vmo, 0, bss_vmo_size, flags)
252 .map_err(ElfLoadError::VmarMap)?;
253 }
254 }
255 }
256 Ok(())
257}
258
259const VMO_NAME_PREFIX_BSS: &str = "bss:";
261const VMO_NAME_PREFIX_DATA: &str = "data:";
262
263fn vmo_name_with_prefix(name: &zx::Name, prefix: &str) -> zx::Name {
265 assert!(prefix.len() <= zx::sys::ZX_MAX_NAME_LEN - 1);
266 if name.is_empty() {
267 zx::Name::new_lossy(&format!("{prefix}<unknown ELF>"))
268 } else {
269 zx::Name::new_lossy(&format!("{prefix}{name}"))
270 }
271}
272
273fn elf_to_vmar_can_map_flags(elf_flags: &elf_parse::SegmentFlags) -> zx::VmarFlags {
274 let mut flags = zx::VmarFlags::empty();
275 if elf_flags.contains(elf_parse::SegmentFlags::READ) {
276 flags |= zx::VmarFlags::CAN_MAP_READ;
277 }
278 if elf_flags.contains(elf_parse::SegmentFlags::WRITE) {
279 flags |= zx::VmarFlags::CAN_MAP_WRITE;
280 }
281 if elf_flags.contains(elf_parse::SegmentFlags::EXECUTE) {
282 flags |= zx::VmarFlags::CAN_MAP_EXECUTE | zx::VmarFlags::CAN_MAP_READ;
283 }
284 flags
285}
286
287fn elf_to_vmar_perm_flags(elf_flags: &elf_parse::SegmentFlags) -> zx::VmarFlags {
288 let mut flags = zx::VmarFlags::empty();
289 if elf_flags.contains(elf_parse::SegmentFlags::READ) {
290 flags |= zx::VmarFlags::PERM_READ;
291 }
292 if elf_flags.contains(elf_parse::SegmentFlags::WRITE) {
293 flags |= zx::VmarFlags::PERM_WRITE;
294 }
295 if elf_flags.contains(elf_parse::SegmentFlags::EXECUTE) {
296 flags |= zx::VmarFlags::PERM_EXECUTE | zx::VmarFlags::PERM_READ_IF_XOM_UNSUPPORTED;
297 }
298 flags
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304 use assert_matches::assert_matches;
305 use std::cell::RefCell;
306 use std::mem::size_of;
307 use std::sync::LazyLock;
308
309 #[test]
310 fn test_vmo_name_with_prefix() {
311 let empty_vmo_name = zx::Name::default();
312 let short_vmo_name = zx::Name::new("short_vmo_name").unwrap();
313 let max_vmo_name = zx::Name::new("a_great_maximum_length_vmo_name").unwrap();
314
315 assert_eq!(vmo_name_with_prefix(&empty_vmo_name, VMO_NAME_PREFIX_BSS), "bss:<unknown ELF>");
316 assert_eq!(
317 vmo_name_with_prefix(&short_vmo_name, VMO_NAME_PREFIX_BSS),
318 "bss:short_vmo_name",
319 );
320 assert_eq!(
321 vmo_name_with_prefix(&max_vmo_name, VMO_NAME_PREFIX_BSS),
322 "bss:a_great_maximum_length_vmo_",
323 );
324 assert_eq!(
325 vmo_name_with_prefix(&max_vmo_name, VMO_NAME_PREFIX_DATA),
326 "data:a_great_maximum_length_vmo",
327 );
328
329 assert_eq!(
330 vmo_name_with_prefix(&empty_vmo_name, "a_long_vmo_name_prefix:"),
331 "a_long_vmo_name_prefix:<unknown",
332 );
333 assert_eq!(
334 vmo_name_with_prefix(&empty_vmo_name, "a_great_maximum_length_vmo_name"),
335 max_vmo_name,
336 );
337 assert_eq!(
338 vmo_name_with_prefix(&max_vmo_name, "anystringhere"),
339 "anystringherea_great_maximum_le"
340 );
341 }
342
343 #[derive(Debug)]
344 struct RecordedMapping {
345 vmo: zx::Vmo,
346 vmo_offset: u64,
347 length: usize,
348 flags: zx::VmarFlags,
349 }
350
351 struct TrackingMapper(RefCell<Vec<RecordedMapping>>);
353
354 impl TrackingMapper {
355 fn new() -> Self {
356 Self(RefCell::new(Vec::new()))
357 }
358 }
359
360 impl IntoIterator for TrackingMapper {
361 type Item = RecordedMapping;
362 type IntoIter = std::vec::IntoIter<Self::Item>;
363
364 fn into_iter(self) -> Self::IntoIter {
365 self.0.into_inner().into_iter()
366 }
367 }
368
369 impl Mapper for TrackingMapper {
370 fn map(
371 &self,
372 vmar_offset: usize,
373 vmo: &zx::Vmo,
374 vmo_offset: u64,
375 length: usize,
376 flags: zx::VmarFlags,
377 ) -> Result<usize, zx::Status> {
378 self.0.borrow_mut().push(RecordedMapping {
379 vmo: vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
380 vmo_offset,
381 length,
382 flags,
383 });
384 Ok(vmar_offset)
385 }
386 }
387
388 const ELF_FILE_HEADER: &elf_parse::Elf64FileHeader = &elf_parse::Elf64FileHeader {
390 ident: elf_parse::ElfIdent {
391 magic: elf_parse::ELF_MAGIC,
392 class: elf_parse::ElfClass::Elf64 as u8,
393 data: elf_parse::NATIVE_ENCODING as u8,
394 version: elf_parse::ElfVersion::Current as u8,
395 osabi: 0x00,
396 abiversion: 0x00,
397 pad: [0; 7],
398 },
399 elf_type: elf_parse::ElfType::SharedObject as u16,
400 machine: elf_parse::CURRENT_ARCH as u16,
401 version: elf_parse::ElfVersion::Current as u32,
402 entry: 0x10000,
403 phoff: size_of::<elf_parse::Elf64FileHeader>(),
404 shoff: 0,
405 flags: 0,
406 ehsize: size_of::<elf_parse::Elf64FileHeader>() as u16,
407 phentsize: size_of::<elf_parse::Elf64ProgramHeader>() as u16,
408 phnum: 1,
409 shentsize: 0,
410 shnum: 0,
411 shstrndx: 0,
412 };
413
414 const VMO_DEFAULT_RIGHTS: zx::Rights = zx::Rights::from_bits_truncate(
417 zx::Rights::DUPLICATE.bits()
418 | zx::Rights::TRANSFER.bits()
419 | zx::Rights::READ.bits()
420 | zx::Rights::WRITE.bits()
421 | zx::Rights::MAP.bits()
422 | zx::Rights::GET_PROPERTY.bits()
423 | zx::Rights::SET_PROPERTY.bits(),
424 );
425
426 #[test]
427 fn map_read_only_with_page_unaligned_bss() {
428 const ELF_DATA: &[u8; 8] = b"FUCHSIA!";
429
430 static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| zx::system_get_page_size() as usize);
432 static ELF_PROGRAM_HEADER: LazyLock<elf_parse::Elf64ProgramHeader> =
433 LazyLock::new(|| elf_parse::Elf64ProgramHeader {
434 segment_type: elf_parse::SegmentType::Load as u32,
435 flags: elf_parse::SegmentFlags::from_bits_truncate(
436 elf_parse::SegmentFlags::READ.bits() | elf_parse::SegmentFlags::EXECUTE.bits(),
437 )
438 .bits(),
439 offset: *PAGE_SIZE,
440 vaddr: 0x10000,
441 paddr: 0x10000,
442 filesz: ELF_DATA.len() as u64,
443 memsz: 0x100,
444 align: *PAGE_SIZE as u64,
445 });
446 let headers = elf_parse::Elf64Headers::new_for_test(
447 ELF_FILE_HEADER,
448 Some(std::slice::from_ref(&ELF_PROGRAM_HEADER)),
449 );
450 let vmo = zx::Vmo::create(*PAGE_SIZE as u64 * 2).expect("create VMO");
451
452 let data = vec![0xff; *PAGE_SIZE * 2];
454 vmo.write(&data, 0).expect("fill VMO with 0xff");
455 vmo.write(ELF_DATA, *PAGE_SIZE as u64).expect("write data to VMO");
457
458 let vmo =
460 vmo.replace_handle(VMO_DEFAULT_RIGHTS - zx::Rights::WRITE).expect("remove WRITE right");
461
462 let mapper = TrackingMapper::new();
463 map_elf_segments(&vmo, &headers, &mapper, 0, 0).expect("map ELF segments");
464
465 let mut mapping_iter = mapper.into_iter();
466
467 let mapping = mapping_iter.next().expect("mapping from ELF VMO");
469
470 let mut data = vec![0; *PAGE_SIZE];
472 mapping.vmo.read(&mut data, mapping.vmo_offset).expect("read VMO");
473
474 let expected = ELF_DATA
477 .iter()
478 .cloned()
479 .chain(std::iter::repeat(0).take(*PAGE_SIZE - ELF_DATA.len()))
480 .collect::<Vec<u8>>();
481
482 assert_eq!(&expected, &data);
483
484 assert_matches!(mapping_iter.next(), None);
486 }
487
488 #[test]
489 fn map_read_only_vmo_with_page_aligned_bss() {
490 static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| zx::system_get_page_size() as usize);
492 static ELF_PROGRAM_HEADER: LazyLock<elf_parse::Elf64ProgramHeader> =
493 LazyLock::new(|| elf_parse::Elf64ProgramHeader {
494 segment_type: elf_parse::SegmentType::Load as u32,
495 flags: elf_parse::SegmentFlags::from_bits_truncate(
496 elf_parse::SegmentFlags::READ.bits() | elf_parse::SegmentFlags::EXECUTE.bits(),
497 )
498 .bits(),
499 offset: *PAGE_SIZE,
500 vaddr: 0x10000,
501 paddr: 0x10000,
502 filesz: *PAGE_SIZE as u64,
503 memsz: *PAGE_SIZE as u64 * 2,
504 align: *PAGE_SIZE as u64,
505 });
506 let headers = elf_parse::Elf64Headers::new_for_test(
507 ELF_FILE_HEADER,
508 Some(std::slice::from_ref(&ELF_PROGRAM_HEADER)),
509 );
510 let vmo = zx::Vmo::create(*PAGE_SIZE as u64 * 2).expect("create VMO");
511 let pattern = vec![0xff; *PAGE_SIZE * 2];
513 vmo.write(&pattern, 0).expect("fill VMO with 0xff");
514
515 let vmo =
518 vmo.replace_handle(VMO_DEFAULT_RIGHTS - zx::Rights::WRITE).expect("remove WRITE right");
519
520 let mapper = TrackingMapper::new();
521 map_elf_segments(&vmo, &headers, &mapper, 0, 0).expect("map ELF segments");
522
523 let mut mapping_iter = mapper.into_iter();
524
525 let mapping = mapping_iter.next().expect("mapping from ELF VMO");
529 assert_eq!(mapping.vmo.koid().unwrap(), vmo.koid().unwrap());
530
531 let mut data = vec![0; *PAGE_SIZE];
532
533 mapping.vmo.read(&mut data, mapping.vmo_offset).expect("read ELF VMO");
535 assert_eq!(&data, &pattern[0..*PAGE_SIZE]);
536
537 let mapping = mapping_iter.next().expect("mapping from BSS VMO");
538
539 mapping.vmo.read(&mut data, mapping.vmo_offset).expect("read BSS VMO");
541 let zero = vec![0; *PAGE_SIZE];
542 assert_eq!(&data, &zero);
543
544 assert_matches!(mapping_iter.next(), None);
546 }
547
548 #[test]
549 fn map_read_only_vmo_with_no_bss() {
550 static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| zx::system_get_page_size() as usize);
552 static ELF_PROGRAM_HEADER: LazyLock<elf_parse::Elf64ProgramHeader> =
553 LazyLock::new(|| elf_parse::Elf64ProgramHeader {
554 segment_type: elf_parse::SegmentType::Load as u32,
555 flags: elf_parse::SegmentFlags::from_bits_truncate(
556 elf_parse::SegmentFlags::READ.bits() | elf_parse::SegmentFlags::EXECUTE.bits(),
557 )
558 .bits(),
559 offset: *PAGE_SIZE,
560 vaddr: 0x10000,
561 paddr: 0x10000,
562 filesz: *PAGE_SIZE as u64,
563 memsz: *PAGE_SIZE as u64,
564 align: *PAGE_SIZE as u64,
565 });
566 let headers = elf_parse::Elf64Headers::new_for_test(
567 ELF_FILE_HEADER,
568 Some(std::slice::from_ref(&ELF_PROGRAM_HEADER)),
569 );
570 let vmo = zx::Vmo::create(*PAGE_SIZE as u64 * 2).expect("create VMO");
571 let pattern = vec![0xff; *PAGE_SIZE * 2];
573 vmo.write(&pattern, 0).expect("fill VMO with 0xff");
574
575 let vmo =
578 vmo.replace_handle(VMO_DEFAULT_RIGHTS - zx::Rights::WRITE).expect("remove WRITE right");
579
580 let mapper = TrackingMapper::new();
581 map_elf_segments(&vmo, &headers, &mapper, 0, 0).expect("map ELF segments");
582
583 let mut mapping_iter = mapper.into_iter();
584
585 let mapping = mapping_iter.next().expect("mapping from ELF VMO");
589 assert_eq!(mapping.vmo.koid().unwrap(), vmo.koid().unwrap());
590
591 let mut data = vec![0; *PAGE_SIZE];
592
593 mapping.vmo.read(&mut data, mapping.vmo_offset).expect("read ELF VMO");
595 assert_eq!(&data, &pattern[0..*PAGE_SIZE]);
596
597 assert_matches!(mapping_iter.next(), None);
599 }
600
601 #[test]
602 fn map_read_only_vmo_with_write_flag() {
603 static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| zx::system_get_page_size() as usize);
605 static ELF_PROGRAM_HEADER: LazyLock<elf_parse::Elf64ProgramHeader> =
606 LazyLock::new(|| elf_parse::Elf64ProgramHeader {
607 segment_type: elf_parse::SegmentType::Load as u32,
608 flags: elf_parse::SegmentFlags::from_bits_truncate(
609 elf_parse::SegmentFlags::READ.bits() | elf_parse::SegmentFlags::WRITE.bits(),
610 )
611 .bits(),
612 offset: *PAGE_SIZE,
613 vaddr: 0x10000,
614 paddr: 0x10000,
615 filesz: *PAGE_SIZE as u64,
616 memsz: *PAGE_SIZE as u64,
617 align: *PAGE_SIZE as u64,
618 });
619 let headers = elf_parse::Elf64Headers::new_for_test(
620 ELF_FILE_HEADER,
621 Some(std::slice::from_ref(&ELF_PROGRAM_HEADER)),
622 );
623 let vmo = zx::Vmo::create(*PAGE_SIZE as u64 * 2).expect("create VMO");
624
625 let vmo =
628 vmo.replace_handle(VMO_DEFAULT_RIGHTS - zx::Rights::WRITE).expect("remove WRITE right");
629
630 let mapper = TrackingMapper::new();
631 map_elf_segments(&vmo, &headers, &mapper, 0, 0).expect("map ELF segments");
632
633 let mut mapping_iter = mapper.into_iter();
634
635 let mapping = mapping_iter.next().expect("mapping from ELF VMO");
639 assert_ne!(mapping.vmo.koid().unwrap(), vmo.koid().unwrap());
640
641 mapping.vmo.write(b"FUCHSIA!", mapping.vmo_offset).expect("write to COW VMO");
643
644 assert_matches!(mapping_iter.next(), None);
646 }
647
648 #[test]
649 fn segment_with_zero_file_size() {
650 static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| zx::system_get_page_size() as usize);
652 static ELF_PROGRAM_HEADER: LazyLock<elf_parse::Elf64ProgramHeader> =
653 LazyLock::new(|| elf_parse::Elf64ProgramHeader {
654 segment_type: elf_parse::SegmentType::Load as u32,
655 flags: elf_parse::SegmentFlags::from_bits_truncate(
656 elf_parse::SegmentFlags::READ.bits() | elf_parse::SegmentFlags::WRITE.bits(),
657 )
658 .bits(),
659 offset: *PAGE_SIZE,
660 vaddr: 0x10000,
661 paddr: 0x10000,
662 filesz: 0,
663 memsz: 1,
664 align: *PAGE_SIZE as u64,
665 });
666 let headers = elf_parse::Elf64Headers::new_for_test(
667 ELF_FILE_HEADER,
668 Some(std::slice::from_ref(&ELF_PROGRAM_HEADER)),
669 );
670 let vmo = zx::Vmo::create(*PAGE_SIZE as u64 * 2).expect("create VMO");
671
672 let mapper = TrackingMapper::new();
673 map_elf_segments(&vmo, &headers, &mapper, 0, 0).expect("map ELF segments");
674 for mapping in mapper.into_iter() {
675 assert!(mapping.length != 0);
676 }
677 }
678
679 #[test]
680 fn map_execute_only_segment() {
681 static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| zx::system_get_page_size() as usize);
682 static ELF_PROGRAM_HEADER: LazyLock<elf_parse::Elf64ProgramHeader> =
683 LazyLock::new(|| elf_parse::Elf64ProgramHeader {
684 segment_type: elf_parse::SegmentType::Load as u32,
685 flags: elf_parse::SegmentFlags::from_bits_truncate(
686 elf_parse::SegmentFlags::EXECUTE.bits(),
687 )
688 .bits(),
689 offset: *PAGE_SIZE,
690 vaddr: 0x10000,
691 paddr: 0x10000,
692 filesz: 0x10,
693 memsz: 0x10,
694 align: *PAGE_SIZE as u64,
695 });
696 let headers = elf_parse::Elf64Headers::new_for_test(
697 ELF_FILE_HEADER,
698 Some(std::slice::from_ref(&ELF_PROGRAM_HEADER)),
699 );
700 let vmo = zx::Vmo::create(*PAGE_SIZE as u64 * 2).expect("create VMO");
701
702 let mapper = TrackingMapper::new();
703 map_elf_segments(&vmo, &headers, &mapper, 0, 0).expect("map ELF segments");
704
705 let mut mapping_iter = mapper.into_iter();
706 let mapping = mapping_iter.next().expect("mapping from ELF VMO");
707 assert_eq!(
708 mapping.flags,
709 zx::VmarFlags::SPECIFIC
710 | zx::VmarFlags::ALLOW_FAULTS
711 | zx::VmarFlags::PERM_EXECUTE
712 | zx::VmarFlags::PERM_READ_IF_XOM_UNSUPPORTED
713 );
714
715 assert_matches!(mapping_iter.next(), None);
717 }
718}