pub struct CrateNamespace { /* private fields */ }
Expand description

This struct represents a namespace of crates and their “global” (publicly-visible) symbols. A crate namespace struct is basically a container around many crates that have all been loaded and linked against each other, completely separate and in isolation from any other crate namespace (although a given crate may be shared across multiple namespaces).

Each CrateNamespace can be treated as a separate OS personality, but are significantly more efficient than library OS-style personalities. A CrateNamespace is also useful to create a process (task group) abstraction.

CrateNamespaces can also optionally be recursive. For example, a namespace that holds just application crates and symbols can recursively rely upon (link against) the crates and symbols in a lower-level namespace that contains kernel crates and symbols.

Implementations§

source§

impl CrateNamespace

source

pub fn new( name: String, dir: NamespaceDir, recursive_namespace: Option<Arc<CrateNamespace>> ) -> CrateNamespace

Creates a new CrateNamespace that is completely empty (no loaded crates).

Arguments
  • name: the name of this CrateNamespace, used only for convenience purposes.
  • dir: the directory of crate object files for this namespace.
  • recursive_namespace: another CrateNamespace that can optionally be used to recursively resolve missing crates/symbols.
source

pub fn name(&self) -> &str

Returns the name of this CrateNamespace, which is just used for debugging purposes.

source

pub fn dir(&self) -> &NamespaceDir

Returns the directory that this CrateNamespace is based on.

source

pub fn recursive_namespace(&self) -> Option<&Arc<CrateNamespace>>

Returns the recursive namespace that this CrateNamespace is built atop, if one exists.

source

pub fn get_tls_initializer_data(&self) -> TlsDataImage

Returns a new copy of this namespace’s initial TLS area, which can be used as the initial TLS area data image for a new task.

source

pub fn crate_names(&self, recursive: bool) -> Vec<StrRef>

Returns a list of all of the crate names currently loaded into this CrateNamespace, including all crates in any recursive namespaces as well if recursive is true. This is a slow method mostly for debugging, since it allocates a new vector of crate names.

source

pub fn for_each_crate<F>(&self, recursive: bool, f: F)where F: FnMut(&str, &StrongCrateRef) -> bool,

Iterates over all crates in this namespace and calls the given function f on each crate. If recursive is true, crates in recursive namespaces are included in the iteration as well.

The function f is called with two arguments: the name of the crate, and a reference to the crate. The function f must return a boolean value that indicates whether to continue iterating; if true, the iteration will continue, if false, the iteration will stop.

source

pub fn get_crate(&self, crate_name: &str) -> Option<StrongCrateRef>

Acquires the lock on this CrateNamespace’s crate list and returns the crate that matches the given crate_name, if it exists in this namespace. If it does not exist in this namespace, then the recursive namespace is searched as well.

Important note about Return value

Returns a StrongCrateReference that has not been marked as a shared crate reference, so if the caller wants to keep the returned StrongCrateRef as a shared crate that jointly exists in another namespace, they should invoke the CowArc::clone() function on the returned value.

source

pub fn get_crate_and_namespace<'n>( namespace: &'n Arc<CrateNamespace>, crate_name: &str ) -> Option<(StrongCrateRef, &'n Arc<CrateNamespace>)>

Acquires the lock on this CrateNamespace’s crate list and returns the crate that matches the given crate_name, if it exists in this namespace. If it does not exist in this namespace, then the recursive namespace is searched as well.

This function is similar to the get_crate method, but it also returns the CrateNamespace in which the crate was found. It is an associated function rather than a method so it can operate on Arc<CrateNamespace>s.

Important note about Return value

Returns a StrongCrateReference that has not been marked as a shared crate reference, so if the caller wants to keep the returned StrongCrateRef as a shared crate that jointly exists in another namespace, they should invoke the CowArc::clone() function on the returned value.

source

pub fn get_crates_starting_with<'n>( namespace: &'n Arc<CrateNamespace>, crate_name_prefix: &str ) -> Vec<(StrRef, StrongCrateRef, &'n Arc<CrateNamespace>)>

Finds the LoadedCrates whose names start with the given crate_name_prefix.

Return

Returns a list of matching crates, in the form of a tuple containing the crate’s name, a shallow-cloned reference to the crate, and a reference to the namespace in which the matching crate was found. If you want to add the returned crate to another namespace, you MUST fully clone() the returned crate reference in order to mark that crate as shared across namespaces.

Important Usage Note

To avoid greedily matching more crates than expected, you may wish to end the crate_name_prefix with “-”. This may provide results more in line with the caller’s expectations; see the last example below about a trailing “-”. This works because the delimiter between a crate name and its trailing hash value is “-”.

Example
  • This CrateNamespace contains the crates my_crate-843a613894da0c24 and my_crate_new-933a635894ce0f12. Calling get_crates_starting_with("my_crate") will return both crates,
source

pub fn get_crate_starting_with<'n>( namespace: &'n Arc<CrateNamespace>, crate_name_prefix: &str ) -> Option<(StrRef, StrongCrateRef, &'n Arc<CrateNamespace>)>

Finds the LoadedCrate whose name starts with the given crate_name_prefix, if and only if there is a single matching crate in this namespace or any of its recursive namespaces. This is a convenience wrapper around the get_crates_starting_with() method.

Return

Returns a tuple containing the crate’s name, a shallow-cloned reference to the crate, and a reference to the namespace in which the matching crate was found. If you want to add the returned crate to another namespace, you MUST fully clone() the returned crate reference in order to mark that crate as shared across namespaces.

Important Usage Note

To avoid greedily matching more crates than expected, you may wish to end the crate_name_prefix with “-”. This may provide results more in line with the caller’s expectations; see the last example below about a trailing “-”. This works because the delimiter between a crate name and its trailing hash value is “-”.

Example
  • This CrateNamespace contains the crates my_crate-843a613894da0c24 and my_crate_new-933a635894ce0f12. Calling get_crate_starting_with("my_crate") will return None, because it will match both my_crate and my_crate_new. To match only my_crate, call this function as get_crate_starting_with("my_crate-").
source

pub fn get_crate_object_files_starting_with<'n>( namespace: &'n Arc<CrateNamespace>, file_name_prefix: &str ) -> Vec<(FileRef, &'n Arc<CrateNamespace>)>

Like get_crates_starting_with(), but for crate object files instead of loaded crates.

Returns a list of matching object files and the namespace in which they were found, inclusive of recursive namespaces.

source

pub fn get_crate_object_file_starting_with<'n>( namespace: &'n Arc<CrateNamespace>, file_name_prefix: &str ) -> Option<(FileRef, &'n Arc<CrateNamespace>)>

Like get_crate_starting_with(), but for crate object files instead of loaded crates.

Returns the matching object file and the namespace in which it was found, if and only if there was a single match (inclusive of recursive namespaces).

source

pub fn method_get_crate_object_files_starting_with( &self, file_name_prefix: &str ) -> Vec<(FileRef, &CrateNamespace)>

Same as get_crate_object_files_starting_with(), but is a method instead of an associated function, and also returns &CrateNamespace instead of &Arc<CrateNamespace>.

This is only necessary because I can’t figure out how to make a generic function that accepts and returns either &CrateNamespace or &Arc<CrateNamespace>.

source

pub fn method_get_crate_object_file_starting_with( &self, file_name_prefix: &str ) -> Option<(FileRef, &CrateNamespace)>

Same as get_crate_object_file_starting_with(), but is a method instead of an associated function, and also returns &CrateNamespace instead of &Arc<CrateNamespace>.

This is only necessary because I can’t figure out how to make a generic function that accepts and returns either &CrateNamespace or &Arc<CrateNamespace>.

source

pub fn load_crate_as_application( namespace: &Arc<CrateNamespace>, crate_object_file: &FileRef, kernel_mmi_ref: &MmiRef, verbose_log: bool ) -> Result<AppCrateRef, &'static str>

Loads the specified application crate into this CrateNamespace, allowing it to be run.

The new application crate’s public symbols are added to this CrateNamespace’s symbol map, allowing other crates in this namespace to depend upon it.

Application crates are added to the CrateNamespace just like kernel crates, so to load an application crate multiple times to spawn multiple instances of it, you can create a new top-level namespace to hold that application crate.

Returns a Result containing the newly-loaded application crate itself.

source

pub fn load_crate( &self, crate_object_file: &FileRef, temp_backup_namespace: Option<&CrateNamespace>, kernel_mmi_ref: &MmiRef, verbose_log: bool ) -> Result<(StrongCrateRef, usize), &'static str>

Loads the specified crate into memory, allowing it to be invoked.
Returns a Result containing the number of symbols that were added to the symbol map as a result of loading this crate.

Arguments
  • crate_object_file: the crate object file that will be loaded into this CrateNamespace.
  • temp_backup_namespace: the CrateNamespace that should be searched for missing symbols (for relocations) if a symbol cannot be found in this CrateNamespace. If temp_backup_namespace is None, then no other namespace will be searched, and any missing symbols will return an Err.
  • kernel_mmi_ref: a mutable reference to the kernel’s MemoryManagementInfo.
  • verbose_log: a boolean value whether to enable verbose_log logging of crate loading actions.
source

pub fn load_crates<'f, I>( &self, crate_files: I, temp_backup_namespace: Option<&CrateNamespace>, kernel_mmi_ref: &MmiRef, verbose_log: bool ) -> Result<(), &'static str>where I: Iterator<Item = &'f FileRef>,

This function first loads all of the given crates’ sections and adds them to the symbol map, and only after all crates are loaded does it move on to linking/relocation calculations.

This allows multiple object files with circular dependencies on one another to be loaded all at once, as if they were a single entity.

Example

If crate A depends on crate B, and crate B depends on crate A, this function will load both crate A and B before trying to resolve their dependencies individually.

source

pub fn clone_on_write(&self) -> CrateNamespace

Duplicates this CrateNamespace into a new CrateNamespace, but uses a copy-on-write/clone-on-write semantic that creates a special shared reference to each crate that indicates it is shared across multiple namespaces.

In other words, crates in the new namespace returned by this fucntions are fully shared with crates in this namespace, until either namespace attempts to modify a shared crate in the future.

When modifying crates in the new namespace, e.g., swapping crates, any crates in the new namespace that are still shared with the old namespace must be deeply copied into a new crate that is exclusively owned, and then that new crate will be modified in whichever way desired. For example, if you swapped one crate A in the new namespace returned from this function and loaded a new crate A2 in its place, and two other crates B and C depended on that newly swapped-out A, then B and C would be transparently deep copied before modifying them to depend on the new crate A2, and you would be left with B2 and C2 as deep copies of B and C, that now depend on A2 instead of A. The existing versions of B and C would still depend on A, but they would no longer be part of the new namespace.

source

pub fn rewrite_section_dependents( old_section: &StrongSectionRef, new_section: &StrongSectionRef, kernel_mmi_ref: &MmiRef ) -> Result<(), &'static str>

Finds all of the weak dependents (sections that depend on the given old_section) and rewrites their relocation entries to point to the given new_section. This effectively replaces the usage of the old_section with the new_section, but does not make any modifications to symbol maps.

source

pub fn add_symbols<'a, I>(&self, sections: I, _log_replacements: bool) -> usizewhere I: IntoIterator<Item = &'a StrongSectionRef>,

Adds only global symbols in the given sections iterator to this namespace’s symbol map,

If a symbol already exists in the symbol map, this replaces the existing symbol but does not count it as a newly-added one.

Returns the number of new unique symbols added.

source

pub fn get_crate_containing_address( &self, virt_addr: VirtualAddress, search_all_section_types: bool ) -> Option<StrongCrateRef>

Finds the crate that contains the given VirtualAddress in its loaded code.

By default, only executable sections (.text) are searched, since typically the only use case for this function is to search for an instruction pointer (program counter) address. However, if search_all_section_types is true, both the read-only and read-write sections will be included in the search, e.g., .rodata, .data, .bss.

Usage

This is mostly useful for printing symbol names for a stack trace (backtrace). It is also similar in functionality to the tool addr2line, but gives the section itself rather than the line of code.

Locking

This can obtain the lock on every crate and every section, so to avoid deadlock, please ensure that the caller task does not hold any such locks. It does not need to obtain locks on the underlying MappedPages regions.

Note

This is a slow procedure because, in the worst case, it will iterate through every loaded crate in this namespace (and its recursive namespace).

source

pub fn get_section_containing_address( &self, virt_addr: VirtualAddress, search_all_section_types: bool ) -> Option<(StrongSectionRef, usize)>

Finds the section that contains the given VirtualAddress in its loaded code.

By default, only executable sections (.text) are searched, since the typical use case for this function is to search for an instruction pointer (program counter) address. However, if search_all_section_types is true, both the read-only and read-write sections will be included in the search, e.g., .rodata, .data, .bss.

Usage

This is mostly useful for printing symbol names for a stack trace (backtrace). It is also similar in functionality to the tool addr2line, but gives the section itself rather than the line of code.

Locking

This can obtain the lock on every crate in this namespace and its recursive namespaces, so to avoid deadlock, please ensure that the caller task does not hold any such locks.

Note

This is a slow procedure because, in the worst case, it will iterate through every section in every loaded crate in this namespace (and its recursive namespace), not just the publicly-visible (global) sections.

source

pub fn get_symbol_and_namespace( &self, demangled_full_symbol: &str ) -> Option<(WeakSectionRef, &CrateNamespace)>

Like get_symbol(), but also returns the exact CrateNamespace where the symbol was found.

source

pub fn get_symbol(&self, demangled_full_symbol: &str) -> WeakSectionRef

Finds the corresponding LoadedSection reference for the given fully-qualified symbol string. Searches this namespace first, and then its recursive namespace as well.

source

pub fn get_symbol_or_load( &self, demangled_full_symbol: &str, temp_backup_namespace: Option<&CrateNamespace>, kernel_mmi_ref: &MmiRef, verbose_log: bool ) -> WeakSectionRef

Finds the corresponding LoadedSection reference for the given fully-qualified symbol string, similar to the simpler function get_symbol(), but takes the additional step of trying to automatically find and/or load the crate containing that symbol (and does so recursively for any of its crate dependencies).

(1) First, it recursively searches this namespace’s and its recursive namespaces’ symbol maps, and returns the symbol if already loaded.

(2) Second, if the symbol is missing from this namespace, it looks in the temp_backup_namespace. If we find it there, then we add that symbol and its containing crate as a shared crate in this namespace.

(3) Third, if this namespace has fuzzy_symbol_matching enabled, it searches the backup namespace for symbols that match the given demangled_full_symbol without the hash suffix.

(4) Fourth, if the missing symbol isn’t in the backup namespace either, try to load its containing crate from the object file. This can only be done for symbols that have a leading crate name, such as “my_crate::foo”; if a symbol was given the no_mangle attribute, then we will not be able to find it, and that symbol’s containing crate should be manually loaded before invoking this.

Arguments
  • demangled_full_symbol: a fully-qualified symbol string, e.g., “my_crate::MyStruct::foo::h843a9ea794da0c24”.
  • temp_backup_namespace: the CrateNamespace that should be temporarily searched (just during this call) for the missing symbol. If temp_backup_namespace is None, then only this namespace (and its recursive namespaces) will be searched.
  • kernel_mmi_ref: a reference to the kernel’s MemoryManagementInfo, which must not be locked.
source

pub fn find_symbols_starting_with( &self, symbol_prefix: &str ) -> Vec<(String, WeakSectionRef)>

Returns a copied list of the corresponding LoadedSections with names that start with the given symbol_prefix. This will also search the recursive namespace’s symbol map.

This method causes allocation because it creates a copy of the matching entries in the symbol map.

Example

The symbol map contains my_crate::foo::h843a613894da0c24 and my_crate::foo::h933a635894ce0f12. Calling find_symbols_starting_with("my_crate::foo") will return a vector containing both sections, which can then be iterated through.

source

pub fn find_symbols_starting_with_and_namespace( &self, symbol_prefix: &str ) -> Vec<(String, WeakSectionRef, &CrateNamespace)>

Similar to find_symbols_starting_with, but also includes a reference to the exact CrateNamespace where the matching symbol was found.

source

pub fn get_symbol_starting_with(&self, symbol_prefix: &str) -> WeakSectionRef

Returns a weak reference to the LoadedSection whose name beings with the given symbol_prefix, if and only if the symbol map only contains a single possible matching symbol. This will also search the recursive namespace’s symbol map.

Important Usage Note

To avoid greedily matching more symbols than expected, you may wish to end the symbol_prefix with “::”. This may provide results more in line with the caller’s expectations; see the last example below about a trailing “::”. This works because the delimiter between a symbol and its trailing hash value is “::”.

Example
  • The symbol map contains my_crate::foo::h843a613894da0c24 and no other symbols that start with my_crate::foo. Calling get_symbol_starting_with("my_crate::foo") will return a weak reference to the section my_crate::foo::h843a613894da0c24.
  • The symbol map contains my_crate::foo::h843a613894da0c24 and my_crate::foo::h933a635894ce0f12. Calling get_symbol_starting_with("my_crate::foo") will return an empty (default) weak reference, which is the same as returing None.
  • (Important) The symbol map contains my_crate::foo::h843a613894da0c24 and my_crate::foo_new::h933a635894ce0f12. Calling get_symbol_starting_with("my_crate::foo") will return an empty (default) weak reference, which is the same as returing None, because it will match both foo and foo_new. To match only foo, call this function as get_symbol_starting_with("my_crate::foo::") (note the trailing “::”).
source

pub fn dump_symbol_map(&self) -> String

Simple debugging function that returns the entire symbol map as a String. This includes only symbols from this namespace, and excludes symbols from recursive namespaces.

source

pub fn dump_symbol_map_recursive(&self) -> String

Same as dump_symbol_map(), but includes symbols from recursive namespaces.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.