squid/backends/clang/
runtime.rs

1use std::{
2    collections::HashMap,
3    ops::{
4        BitAnd,
5        BitOrAssign,
6        Not,
7        ShlAssign,
8    },
9};
10
11use num_traits::NumCast;
12use rustc_hash::FxHashMap;
13use thiserror::Error;
14
15use crate::{
16    backends::clang::{
17        perms::*,
18        AOTExecutor,
19        AOTReturnCode,
20        AddressSpace,
21        EventChannel,
22        Heap,
23        HeapChunk,
24        HeapError,
25        Memory,
26        Registers,
27        Symbol,
28    },
29    frontend::VAddr,
30    kernel::linux::LinuxError,
31    riscv::register::{
32        CsrRegister,
33        FpRegister,
34        GpRegister,
35    },
36    runtime::{
37        Runtime,
38        SnapshotId,
39    },
40};
41
42/// This type shows all errors that can occur during runtime
43#[allow(missing_docs)]
44#[derive(Error, Debug, Clone)]
45pub enum ClangRuntimeFault {
46    #[error("There was an error with the internal state of the code: {0}")]
47    InternalError(String),
48
49    #[error("Encountered an invalid pc address: {0:#x}")]
50    InvalidPc(VAddr),
51
52    #[error("The given snapshot id does not exist: {0}")]
53    InvalidSnapshotId(SnapshotId),
54
55    #[error("The application tried to read {0} values from the event channel but only {1} were present")]
56    InvalidEventChannel(usize, usize),
57
58    #[error("Reading {1} bytes at address {0:#x} failed")]
59    MemoryReadError(VAddr, usize),
60
61    #[error("Writing {1} bytes at address {0:#x} failed")]
62    MemoryWriteError(VAddr, usize),
63
64    #[error("Target attempted to divide by zero")]
65    DivisionByZero,
66
67    #[error("A memory management error occured: {0}")]
68    MemoryManagementError(String),
69
70    #[error("HeapError: {0}")]
71    HeapError(#[from] HeapError),
72
73    #[error("LinuxError: {0}")]
74    LinuxError(#[from] LinuxError),
75
76    #[error("Timeout")]
77    Timeout,
78
79    #[error("Execution cannot continue")]
80    End,
81
82    #[error("The application had an integer overflow with {0} and {1}")]
83    IntegerOverflow(u64, u64),
84}
85
86pub(crate) trait RiscvType: Sized + Copy {
87    const SIZE: usize;
88
89    #[inline]
90    fn from_slice(data: &[u8]) -> Self {
91        debug_assert_eq!(data.len(), Self::SIZE);
92        unsafe { *std::mem::transmute::<*const u8, *const Self>(data.as_ptr()) }
93    }
94}
95
96impl RiscvType for u64 {
97    const SIZE: usize = 8;
98}
99
100impl RiscvType for u32 {
101    const SIZE: usize = 4;
102}
103
104impl RiscvType for u16 {
105    const SIZE: usize = 2;
106}
107
108impl RiscvType for u8 {
109    const SIZE: usize = 1;
110}
111
112#[inline]
113pub(crate) fn broadcast_perm<T>(perm: u8) -> T
114where
115    T: RiscvType + Default + ShlAssign<i32> + BitOrAssign + NumCast + Copy,
116{
117    let mut ret = T::default();
118    let perms = T::from(perm).unwrap();
119
120    for _ in 0..T::SIZE {
121        ret <<= 8;
122        ret |= perms;
123    }
124
125    ret
126}
127
128fn load_riscv_type<T>(memory: &Memory, offset: usize) -> Option<T>
129where
130    T: RiscvType + Default + ShlAssign<i32> + BitOrAssign + NumCast + Copy + BitAnd,
131    <T as BitAnd>::Output: PartialEq<T>,
132{
133    if !memory.is_in_bounds(offset, T::SIZE) {
134        return None;
135    }
136
137    /* Check permissions */
138    let perms = T::from_slice(memory.perms(offset, T::SIZE));
139    let uninit_mask = broadcast_perm::<T>(PERM_UNINIT);
140
141    if (perms & uninit_mask) != T::default() {
142        return None;
143    }
144
145    let read_mask = broadcast_perm::<T>(PERM_READ);
146
147    if (perms & read_mask) != read_mask {
148        return None;
149    }
150
151    /* Read content */
152    let content = T::from_slice(memory.content(offset, T::SIZE));
153    Some(content)
154}
155
156#[inline]
157fn load_slice(memory: &Memory, offset: usize, size: usize) -> Option<&[u8]> {
158    if !memory.is_in_bounds(offset, size) {
159        return None;
160    }
161
162    /* Check permissions */
163    for perm in memory.perms(offset, size) {
164        if (*perm & PERM_UNINIT) != 0 || (*perm & PERM_READ) != PERM_READ {
165            return None;
166        }
167    }
168
169    /* Read content */
170    let content = memory.content(offset, size);
171    Some(content)
172}
173
174fn store_riscv_type<T>(memory: &mut Memory, offset: usize, value: T) -> bool
175where
176    T: RiscvType + Default + ShlAssign<i32> + BitOrAssign + NumCast + Copy + BitAnd<Output = T> + Not<Output = T>,
177    <T as BitAnd>::Output: PartialEq<T>,
178{
179    if !memory.is_in_bounds(offset, T::SIZE) {
180        return false;
181    }
182
183    /* Check permissions */
184    let perms = T::from_slice(memory.perms(offset, T::SIZE));
185    let write_mask = broadcast_perm::<T>(PERM_WRITE);
186
187    if (perms & write_mask) != write_mask {
188        return false;
189    }
190
191    let uninit_mask = broadcast_perm::<T>(PERM_UNINIT);
192    let perms = perms & !uninit_mask;
193
194    unsafe {
195        *std::mem::transmute::<*mut u8, *mut T>(memory.perms_mut(offset, T::SIZE).as_mut_ptr()) = perms;
196    }
197
198    /* Store content */
199    unsafe {
200        *std::mem::transmute::<*mut u8, *mut T>(memory.content_mut(offset, T::SIZE).as_mut_ptr()) = value;
201    }
202
203    true
204}
205
206#[inline]
207fn store_slice(memory: &mut Memory, offset: usize, value: &[u8]) -> bool {
208    let size = value.len();
209
210    if !memory.is_in_bounds(offset, size) {
211        return false;
212    }
213
214    /* Check permissions */
215    for perm in memory.perms_mut(offset, size) {
216        if (*perm & PERM_WRITE) != PERM_WRITE {
217            return false;
218        }
219
220        *perm &= !PERM_UNINIT;
221    }
222
223    /* Read content */
224    memory.content_mut(offset, size).copy_from_slice(value);
225
226    true
227}
228
229#[inline]
230fn load_perms(memory: &Memory, offset: usize, size: usize) -> Option<&[u8]> {
231    if !memory.is_in_bounds(offset, size) {
232        return None;
233    }
234
235    Some(memory.perms(offset, size))
236}
237
238#[inline]
239fn load_perms_mut(memory: &mut Memory, offset: usize, size: usize) -> Option<&mut [u8]> {
240    if !memory.is_in_bounds(offset, size) {
241        return None;
242    }
243
244    Some(memory.perms_mut(offset, size))
245}
246
247#[inline]
248fn load_string(memory: &Memory, offset: usize) -> Option<&[u8]> {
249    if !memory.is_in_bounds(offset, 1) {
250        return None;
251    }
252
253    for i in offset..memory.size() {
254        let perm = memory.perms(i, 1)[0];
255
256        if (perm & PERM_UNINIT) != 0 || (perm & PERM_READ) == 0 {
257            return None;
258        }
259
260        let byte = memory.content(i, 1)[0];
261
262        if byte == 0 {
263            let slice = memory.content(offset, i - offset);
264            return Some(slice);
265        }
266    }
267
268    None
269}
270
271#[inline]
272fn store_string(memory: &mut Memory, offset: usize, value: &[u8]) -> bool {
273    let len = value.len() + 1;
274
275    if !memory.is_in_bounds(offset, len) {
276        return false;
277    }
278
279    /* Check permissions */
280    for perm in memory.perms_mut(offset, len) {
281        if (*perm & PERM_WRITE) != PERM_WRITE {
282            return false;
283        }
284
285        *perm &= !PERM_UNINIT;
286    }
287
288    /* Read content */
289    let target = memory.content_mut(offset, len);
290    target[0..value.len()].copy_from_slice(value);
291    target[value.len()] = 0;
292
293    true
294}
295
296struct SnapshotData {
297    next_pc: VAddr,
298    next_event_channel_length: usize,
299    var_storage: Vec<u64>,
300}
301
302/// The ClangRuntime gives you access to registers, memory, the event channel and the AOT-compiled code of the ClangBackend.
303pub struct ClangRuntime {
304    memory: Memory,
305    event_channel: EventChannel,
306    registers: Registers,
307    executor: AOTExecutor,
308    next_pc: VAddr,
309    symbols: HashMap<String, Vec<Symbol>>,
310    next_event_channel_length: usize,
311    snapshots: FxHashMap<SnapshotId, SnapshotData>,
312    var_storage: Vec<u64>,
313    heap_mgr: Heap,
314}
315
316impl ClangRuntime {
317    #[allow(clippy::too_many_arguments)]
318    pub(crate) fn new(
319        memory: Memory,
320        event_channel: EventChannel,
321        registers: Registers,
322        executor: AOTExecutor,
323        next_pc: VAddr,
324        symbols: HashMap<String, Vec<Symbol>>,
325        var_storage: Vec<u64>,
326    ) -> Self {
327        Self {
328            heap_mgr: Heap::new(memory.heap(), memory.heap_end()),
329            memory,
330            event_channel,
331            registers,
332            executor,
333            next_pc,
334            symbols,
335            next_event_channel_length: 0,
336            snapshots: FxHashMap::default(),
337            var_storage,
338        }
339    }
340}
341
342impl Runtime for ClangRuntime {
343    type Error = ClangRuntimeFault;
344    type Event = usize;
345
346    fn set_pc(&mut self, pc: VAddr) {
347        self.registers.set_pc(pc);
348        self.next_pc = pc;
349    }
350
351    fn get_pc(&self) -> VAddr {
352        self.registers.get_pc()
353    }
354
355    fn set_gp_register(&mut self, register: GpRegister, value: u64) {
356        self.registers.set_gp(register as usize, value);
357    }
358
359    fn get_gp_register(&self, register: GpRegister) -> u64 {
360        self.registers.get_gp(register as usize)
361    }
362
363    fn set_fp_register(&mut self, register: FpRegister, value: f64) {
364        self.registers.set_fp(register as usize, value.to_bits());
365    }
366
367    fn get_fp_register(&self, register: FpRegister) -> f64 {
368        f64::from_bits(self.registers.get_fp(register as usize))
369    }
370
371    fn set_csr_register(&mut self, register: CsrRegister, value: u64) {
372        self.registers.set_csr(register, value);
373    }
374
375    fn get_csr_register(&self, register: CsrRegister) -> u64 {
376        self.registers.get_csr(register)
377    }
378
379    fn run(&mut self) -> Result<Self::Event, Self::Error> {
380        /* Prepare AOT execution */
381        self.event_channel.set_length(self.next_event_channel_length);
382        self.registers.set_pc(self.next_pc);
383        self.registers.set_last_instr(0);
384
385        /* Execute code */
386        self.next_pc =
387            self.executor.run(&mut self.memory, &mut self.event_channel, &mut self.registers, &mut self.var_storage);
388        self.next_event_channel_length = 0;
389
390        /* Translate aot exit code to runtime event / fault */
391        match self.executor.return_code() {
392            AOTReturnCode::Event => {
393                let id = self.executor.return_arg0();
394                Ok(id)
395            },
396            AOTReturnCode::InvalidState => {
397                Err(ClangRuntimeFault::InternalError("AOT code returned but did not set an event or fault".to_string()))
398            },
399            AOTReturnCode::InvalidJumpTarget => {
400                let addr = self.executor.return_arg0() as VAddr;
401                Err(ClangRuntimeFault::InvalidPc(addr))
402            },
403            AOTReturnCode::UninitializedRead | AOTReturnCode::InvalidRead => {
404                let addr = self.executor.return_arg0() as VAddr;
405                let size = self.executor.return_arg1();
406                Err(ClangRuntimeFault::MemoryReadError(addr, size))
407            },
408            AOTReturnCode::End => Err(ClangRuntimeFault::End),
409            AOTReturnCode::InvalidWrite => {
410                let addr = self.executor.return_arg0() as VAddr;
411                let size = self.executor.return_arg1();
412                Err(ClangRuntimeFault::MemoryWriteError(addr, size))
413            },
414            AOTReturnCode::InvalidEventChannel => {
415                let req_size = self.executor.return_arg0();
416                let act_size = self.executor.return_arg1();
417                Err(ClangRuntimeFault::InvalidEventChannel(req_size, act_size))
418            },
419            AOTReturnCode::DivByZero => Err(ClangRuntimeFault::DivisionByZero),
420            AOTReturnCode::Timeout => Err(ClangRuntimeFault::Timeout),
421            AOTReturnCode::IntegerOverflow => {
422                let a = self.executor.return_arg0();
423                let b = self.executor.return_arg1();
424                Err(ClangRuntimeFault::IntegerOverflow(a as u64, b as u64))
425            },
426        }
427    }
428
429    fn take_snapshot(&mut self, id: SnapshotId) {
430        self.snapshots.insert(
431            id,
432            SnapshotData {
433                next_pc: self.next_pc,
434                next_event_channel_length: self.next_event_channel_length,
435                var_storage: self.var_storage.clone(),
436            },
437        );
438        self.memory.take_snapshot(id);
439        self.event_channel.take_snapshot(id);
440        self.registers.take_snapshot(id);
441        self.heap_mgr.take_snapshot(id);
442    }
443
444    fn restore_snapshot(&mut self, id: SnapshotId) -> Result<(), Self::Error> {
445        if let Some(snapshot) = self.snapshots.get(&id) {
446            self.next_pc = snapshot.next_pc;
447            self.next_event_channel_length = snapshot.next_event_channel_length;
448            unsafe {
449                std::ptr::copy_nonoverlapping(
450                    snapshot.var_storage.as_ptr(),
451                    self.var_storage.as_mut_ptr(),
452                    snapshot.var_storage.len(),
453                )
454            };
455        } else {
456            return Err(ClangRuntimeFault::InvalidSnapshotId(id));
457        }
458        self.memory.restore_snapshot_unchecked(id);
459        self.event_channel.restore_snapshot_unchecked(id);
460        self.registers.restore_snapshot_unchecked(id);
461        self.heap_mgr.restore_snapshot_unchecked(id);
462        Ok(())
463    }
464
465    fn delete_snapshot(&mut self, id: SnapshotId) -> Result<(), Self::Error> {
466        if self.snapshots.remove(&id).is_none() {
467            return Err(ClangRuntimeFault::InvalidSnapshotId(id));
468        }
469        self.memory.delete_snapshot_unchecked(id);
470        self.event_channel.delete_snapshot_unchecked(id);
471        self.registers.delete_snapshot_unchecked(id);
472        self.heap_mgr.delete_snapshot_unchecked(id);
473        Ok(())
474    }
475
476    fn has_snapshot(&self, id: SnapshotId) -> bool {
477        self.snapshots.contains_key(&id)
478    }
479
480    fn event_channel(&self) -> &[u64] {
481        let length = self.event_channel.length();
482        self.event_channel.get(length).unwrap()
483    }
484
485    fn event_channel_mut(&mut self, size: usize) -> Result<&mut [u64], Self::Error> {
486        // Ugly but borrow checker forces us to:
487        let cap = self.event_channel.capacity();
488
489        if let Some(data) = self.event_channel.get_mut(size) {
490            self.next_event_channel_length = std::cmp::max(self.next_event_channel_length, size);
491            Ok(data)
492        } else {
493            Err(ClangRuntimeFault::InvalidEventChannel(size, cap))
494        }
495    }
496
497    fn load_dword(&self, address: VAddr) -> Result<u64, Self::Error> {
498        let result = match AddressSpace::decode(address) {
499            AddressSpace::Code(_) => None,
500            AddressSpace::Data(offset) => load_riscv_type(&self.memory, offset),
501        };
502        result.ok_or(ClangRuntimeFault::MemoryReadError(address, 8))
503    }
504
505    fn load_word(&self, address: VAddr) -> Result<u32, Self::Error> {
506        let result = match AddressSpace::decode(address) {
507            AddressSpace::Code(_) => None,
508            AddressSpace::Data(offset) => load_riscv_type(&self.memory, offset),
509        };
510        result.ok_or(ClangRuntimeFault::MemoryReadError(address, 4))
511    }
512
513    fn load_hword(&self, address: VAddr) -> Result<u16, Self::Error> {
514        let result = match AddressSpace::decode(address) {
515            AddressSpace::Code(_) => None,
516            AddressSpace::Data(offset) => load_riscv_type(&self.memory, offset),
517        };
518        result.ok_or(ClangRuntimeFault::MemoryReadError(address, 2))
519    }
520
521    fn load_byte(&self, address: VAddr) -> Result<u8, Self::Error> {
522        let result = match AddressSpace::decode(address) {
523            AddressSpace::Code(_) => None,
524            AddressSpace::Data(offset) => load_riscv_type(&self.memory, offset),
525        };
526        result.ok_or(ClangRuntimeFault::MemoryReadError(address, 1))
527    }
528
529    fn load_slice(&self, address: VAddr, size: usize) -> Result<&[u8], Self::Error> {
530        let result = match AddressSpace::decode(address) {
531            AddressSpace::Code(_) => None,
532            AddressSpace::Data(offset) => load_slice(&self.memory, offset, size),
533        };
534        result.ok_or(ClangRuntimeFault::MemoryReadError(address, size))
535    }
536
537    fn store_dword(&mut self, address: VAddr, value: u64) -> Result<(), Self::Error> {
538        let result = match AddressSpace::decode(address) {
539            AddressSpace::Code(_) => false,
540            AddressSpace::Data(offset) => store_riscv_type(&mut self.memory, offset, value),
541        };
542        if result {
543            Ok(())
544        } else {
545            Err(ClangRuntimeFault::MemoryWriteError(address, 8))
546        }
547    }
548    fn store_word(&mut self, address: VAddr, value: u32) -> Result<(), Self::Error> {
549        let result = match AddressSpace::decode(address) {
550            AddressSpace::Code(_) => false,
551            AddressSpace::Data(offset) => store_riscv_type(&mut self.memory, offset, value),
552        };
553        if result {
554            Ok(())
555        } else {
556            Err(ClangRuntimeFault::MemoryWriteError(address, 4))
557        }
558    }
559    fn store_hword(&mut self, address: VAddr, value: u16) -> Result<(), Self::Error> {
560        let result = match AddressSpace::decode(address) {
561            AddressSpace::Code(_) => false,
562            AddressSpace::Data(offset) => store_riscv_type(&mut self.memory, offset, value),
563        };
564        if result {
565            Ok(())
566        } else {
567            Err(ClangRuntimeFault::MemoryWriteError(address, 2))
568        }
569    }
570    fn store_byte(&mut self, address: VAddr, value: u8) -> Result<(), Self::Error> {
571        let result = match AddressSpace::decode(address) {
572            AddressSpace::Code(_) => false,
573            AddressSpace::Data(offset) => store_riscv_type(&mut self.memory, offset, value),
574        };
575        if result {
576            Ok(())
577        } else {
578            Err(ClangRuntimeFault::MemoryWriteError(address, 1))
579        }
580    }
581
582    fn store_slice<S: AsRef<[u8]>>(&mut self, address: VAddr, value: S) -> Result<(), Self::Error> {
583        let value = value.as_ref();
584        let result = match AddressSpace::decode(address) {
585            AddressSpace::Code(_) => false,
586            AddressSpace::Data(offset) => store_slice(&mut self.memory, offset, value),
587        };
588        if result {
589            Ok(())
590        } else {
591            Err(ClangRuntimeFault::MemoryWriteError(address, value.len()))
592        }
593    }
594
595    fn load_string(&self, address: VAddr) -> Result<&[u8], Self::Error> {
596        let result = match AddressSpace::decode(address) {
597            AddressSpace::Code(_) => None,
598            AddressSpace::Data(offset) => load_string(&self.memory, offset),
599        };
600        result.ok_or(ClangRuntimeFault::MemoryReadError(address, 0))
601    }
602
603    fn store_string<S: AsRef<str>>(&mut self, address: VAddr, value: S) -> Result<(), Self::Error> {
604        let value = value.as_ref().as_bytes();
605        let result = match AddressSpace::decode(address) {
606            AddressSpace::Code(_) => false,
607            AddressSpace::Data(offset) => store_string(&mut self.memory, offset, value),
608        };
609        if result {
610            Ok(())
611        } else {
612            Err(ClangRuntimeFault::MemoryWriteError(address, value.len()))
613        }
614    }
615}
616
617/// Misc functions of the ClangRuntime
618impl ClangRuntime {
619    /// Get the raw return code of the AOT-compiled code
620    pub fn raw_return_code(&self) -> AOTReturnCode {
621        self.executor.return_code()
622    }
623
624    /// Get access to the permission bytes at the given address
625    pub fn permissions(&self, address: VAddr, size: usize) -> Result<&[u8], ClangRuntimeFault> {
626        let result = match AddressSpace::decode(address) {
627            AddressSpace::Code(_) => None,
628            AddressSpace::Data(offset) => load_perms(&self.memory, offset, size),
629        };
630        result.ok_or(ClangRuntimeFault::MemoryReadError(address, size))
631    }
632
633    /// Get access to the permission bytes at the given address
634    pub fn permissions_mut(&mut self, address: VAddr, size: usize) -> Result<&mut [u8], ClangRuntimeFault> {
635        let result = match AddressSpace::decode(address) {
636            AddressSpace::Code(_) => None,
637            AddressSpace::Data(offset) => load_perms_mut(&mut self.memory, offset, size),
638        };
639        result.ok_or(ClangRuntimeFault::MemoryWriteError(address, size))
640    }
641
642    /// Return the virtual address of the RISC-V instruction that was executed last.
643    /// Note that this is the virtual address from the ELF file, not the virtual addresses
644    /// used by the ClangRuntime!
645    pub fn get_last_instruction(&self) -> VAddr {
646        self.registers.get_last_instr()
647    }
648
649    /// Return a raw u8 pointer to the content of the memory at the given address.
650    #[allow(clippy::missing_safety_doc)]
651    pub unsafe fn raw_pointer(&self, address: VAddr) -> Result<*const u8, ClangRuntimeFault> {
652        match AddressSpace::decode(address) {
653            AddressSpace::Code(_) => Err(ClangRuntimeFault::MemoryReadError(address, 0)),
654            AddressSpace::Data(offset) => {
655                if !self.memory.is_in_bounds(offset, 1) {
656                    return Err(ClangRuntimeFault::MemoryReadError(address, 0));
657                }
658
659                Ok(self.memory.content(offset, 1).as_ptr())
660            },
661        }
662    }
663
664    /// Return a raw u8 pointer to the content of the memory at the given address
665    #[allow(clippy::missing_safety_doc)]
666    pub unsafe fn raw_pointer_mut(&mut self, address: VAddr) -> Result<*mut u8, ClangRuntimeFault> {
667        match AddressSpace::decode(address) {
668            AddressSpace::Code(_) => Err(ClangRuntimeFault::MemoryReadError(address, 0)),
669            AddressSpace::Data(offset) => {
670                if !self.memory.is_in_bounds(offset, 1) {
671                    return Err(ClangRuntimeFault::MemoryReadError(address, 0));
672                }
673
674                Ok(self.memory.content_mut(offset, 1).as_mut_ptr())
675            },
676        }
677    }
678
679    /// Get the number of executed instructions of the last [`ClangRuntime::run`] invocation.
680    /// Note that this counter resets every time [`ClangRuntime::run`] is called.
681    pub fn get_executed_instructions(&self) -> usize {
682        self.executor.executed_instructions()
683    }
684}
685
686/// The symbol store of the ClangRuntime
687impl ClangRuntime {
688    /// Get all the symbols that are at the given address
689    pub fn lookup_symbol_from_address(&self, addr: VAddr) -> Vec<(&str, &Symbol)> {
690        let mut ret = Vec::new();
691
692        for (file, symbols) in &self.symbols {
693            for symbol in symbols {
694                if symbol.contains_address(addr) {
695                    ret.push((file.as_str(), symbol));
696                }
697            }
698        }
699
700        ret
701    }
702
703    /// Get all the symbols that match the given private name
704    pub fn lookup_symbol_from_private_name<S: AsRef<str>>(&self, name: S) -> Vec<(&str, &Symbol)> {
705        let name = name.as_ref();
706        let mut ret = Vec::new();
707
708        for (file, symbols) in &self.symbols {
709            for symbol in symbols {
710                if symbol.is_private() && symbol.name() == name {
711                    ret.push((file.as_str(), symbol));
712                }
713            }
714        }
715
716        ret
717    }
718
719    /// Get all the symbols that match the given public name
720    pub fn lookup_symbol_from_public_name<S: AsRef<str>>(&self, name: S) -> Vec<(&str, &Symbol)> {
721        let name = name.as_ref();
722        let mut ret = Vec::new();
723
724        for (file, symbols) in &self.symbols {
725            for symbol in symbols {
726                if symbol.is_public() && symbol.name() == name {
727                    ret.push((file.as_str(), symbol));
728                }
729            }
730        }
731
732        ret
733    }
734}
735
736/// The dynstore methods of the ClangRuntime
737impl ClangRuntime {
738    /// Allocate a chunk of a given size in the heap of the ClangRuntime.
739    pub fn dynstore_allocate(&mut self, size: usize) -> Result<VAddr, ClangRuntimeFault> {
740        let offset = self.heap_mgr.malloc(&mut self.memory, size)?;
741        Ok(AddressSpace::Data(offset).encode())
742    }
743
744    /// Free a chunk at the given address.
745    pub fn dynstore_deallocate(&mut self, addr: VAddr) -> Result<(), ClangRuntimeFault> {
746        if addr == 0 {
747            return Ok(());
748        }
749
750        let offset = if let AddressSpace::Data(offset) = AddressSpace::decode(addr) {
751            offset
752        } else {
753            return Err(ClangRuntimeFault::MemoryManagementError(format!(
754                "Tried to deallocate a non-heap address: {:#x}",
755                addr
756            )));
757        };
758
759        self.heap_mgr.free(&mut self.memory, offset)?;
760
761        Ok(())
762    }
763
764    /// Get a list of all allocated heap chunks in the heap.
765    pub fn dynstore_get_all_chunks(&self) -> Vec<HeapChunk> {
766        self.heap_mgr.get_heap_chunks(&self.memory)
767    }
768
769    /// Get metadata about the heap chunk at the given address.
770    pub fn dynstore_get_single_chunk(&self, addr: VAddr) -> Result<HeapChunk, ClangRuntimeFault> {
771        let offset = if let AddressSpace::Data(offset) = AddressSpace::decode(addr) {
772            offset
773        } else {
774            return Err(ClangRuntimeFault::MemoryManagementError(format!(
775                "Tried to get a single chunk with a non-heap address: {:#x}",
776                addr
777            )));
778        };
779
780        let chunk = self.heap_mgr.get_heap_chunk(&self.memory, offset)?;
781
782        Ok(chunk)
783    }
784
785    /// Return the number of chunks that have been allocated but not freed yet
786    pub fn dynstore_number_of_chunks(&self) -> usize {
787        self.heap_mgr.allocated_chunks()
788    }
789
790    /// Reallocate the heap chunk at the given address and resize it to the given `new_size`
791    pub fn dynstore_reallocate(&mut self, addr: VAddr, new_size: usize) -> Result<VAddr, ClangRuntimeFault> {
792        if addr == 0 || new_size == 0 {
793            return Err(ClangRuntimeFault::MemoryManagementError(
794                "Called dynstore_reallocate() with invalid parameters".to_string(),
795            ));
796        }
797
798        let offset = if let AddressSpace::Data(offset) = AddressSpace::decode(addr) {
799            offset
800        } else {
801            return Err(ClangRuntimeFault::MemoryManagementError(format!(
802                "Tried to reallocate a non-heap address: {:#x}",
803                addr
804            )));
805        };
806
807        let new_offset = self.heap_mgr.realloc(&mut self.memory, offset, new_size)?;
808        Ok(AddressSpace::Data(new_offset).encode())
809    }
810
811    /// Get the number of bytes used by all heap chunks
812    pub fn dynstore_memory_usage(&self) -> usize {
813        self.heap_mgr.memory_usage(&self.memory)
814    }
815}