Skip to content

Commit

Permalink
Cleanup dynlink, part 1.
Browse files Browse the repository at this point in the history
  • Loading branch information
dbittman committed Jul 1, 2024
1 parent eef11f0 commit b80d586
Show file tree
Hide file tree
Showing 23 changed files with 371 additions and 397 deletions.
6 changes: 0 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 45 additions & 12 deletions src/bin/bootstrap/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::process::exit;

use dynlink::{
engines::{Backing, Engine},
compartment::MONITOR_COMPARTMENT_ID,
engines::{Backing, ContextEngine},
library::UnloadedLibrary,
symbol::LookupFlags,
DynlinkError, DynlinkErrorKind,
};
use tracing::{debug, info, warn, Level};
use tracing_subscriber::FmtSubscriber;
Expand All @@ -20,24 +22,55 @@ fn find_init_name(name: &str) -> Option<ObjID> {
None
}

struct Engine;

impl ContextEngine for Engine {
fn load_segments(
&mut self,
src: &Backing,
ld: &[dynlink::engines::LoadDirective],
) -> Result<Vec<Backing>, dynlink::DynlinkError> {
dynlink::engines::twizzler::load_segments(src, ld)
}

fn load_object(&mut self, unlib: &UnloadedLibrary) -> Result<Backing, DynlinkError> {
let id = name_resolver(&unlib.name)?;
Ok(Backing::new(
twizzler_runtime_api::get_runtime()
.map_object(id, MapFlags::READ)
.map_err(|_err| DynlinkErrorKind::NewBackingFail)?,
))
}

fn select_compartment(
&mut self,
_unlib: &UnloadedLibrary,
) -> Option<dynlink::compartment::CompartmentId> {
Some(MONITOR_COMPARTMENT_ID)
}
}

fn name_resolver(mut name: &str) -> Result<ObjID, DynlinkError> {
if name.starts_with("libstd") {
name = "libstd.so";
}
find_init_name(name).ok_or(
DynlinkErrorKind::NameNotFound {
name: name.to_string(),
}
.into(),
)
}

fn start_runtime(_runtime_monitor: ObjID, _runtime_library: ObjID) -> ! {
//miette::set_hook(Box::new(|_| Box::new(miette::DebugReportHandler::new()))).unwrap();
let engine = Engine;
let mut ctx = dynlink::context::Context::new(engine);
let mut ctx = dynlink::context::Context::new(Box::new(engine));
let unlib = UnloadedLibrary::new("libmonitor.so");
let monitor_comp_id = ctx.add_compartment("monitor").unwrap();

let monitor_id = ctx
.load_library_in_compartment(monitor_comp_id, unlib, |mut name| {
if name.starts_with("libstd") {
name = "libstd.so";
}
let id = find_init_name(name)?;
let obj = twizzler_runtime_api::get_runtime()
.map_object(id, MapFlags::READ)
.ok()?;
Some(Backing::new(obj))
})
.load_library_in_compartment(monitor_comp_id, unlib)
.unwrap();

ctx.relocate_all(monitor_id).unwrap();
Expand Down
6 changes: 2 additions & 4 deletions src/lib/twizzler-abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ authors = ["Daniel Bittman <[email protected]>"]

[dependencies]
bitflags = "2.4.1"
syscall_encode_macros = { version = "0.1.8" }
syscall_encode_traits = { version = "0.1.9" }
#syscall_encode_macros = { version = "0.1.8" }
#syscall_encode_traits = { version = "0.1.9" }
twizzler-runtime-api = { path = "../twizzler-runtime-api" }
alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
talc = { version = "3.0", default-features = false, optional = true }
Expand Down Expand Up @@ -45,8 +45,6 @@ rustc-dep-of-std = [
"compiler_builtins/rustc-dep-of-std",
"libc/rustc-dep-of-std",
"bitflags/rustc-dep-of-std",
"syscall_encode_macros/rustc-dep-of-std",
"syscall_encode_traits/rustc-dep-of-std",
"twizzler-runtime-api/rustc-dep-of-std",
"alloc",
]
23 changes: 18 additions & 5 deletions src/runtime/dynlink/src/compartment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use std::{
use petgraph::stable_graph::NodeIndex;
use talc::{ErrOnOom, Talc};

use crate::{library::BackingData, tls::TlsInfo};
use crate::{engines::Backing, library::LibraryId, tls::TlsInfo};

mod tls;

#[repr(C)]
/// A compartment that contains libraries (and a local runtime).
pub struct Compartment<Backing: BackingData> {
pub struct Compartment {
pub name: String,
pub id: CompartmentId,
// Library names are per-compartment.
Expand All @@ -39,7 +39,15 @@ impl Display for CompartmentId {
}
}

impl<Backing: BackingData> Compartment<Backing> {
impl CompartmentId {
/// Get the raw integer representing compartment ID.
pub fn raw(&self) -> usize {
self.0
}
}

pub const MONITOR_COMPARTMENT_ID: CompartmentId = CompartmentId(0);
impl Compartment {
pub(crate) fn new(name: String, id: CompartmentId) -> Self {
Self {
name,
Expand All @@ -51,15 +59,20 @@ impl<Backing: BackingData> Compartment<Backing> {
tls_gen: 0,
}
}

/// Get an iterator over the IDs of libraries in this compartment.
pub fn library_ids(&self) -> impl Iterator<Item = LibraryId> + '_ {
self.library_names.values().map(|idx| LibraryId(*idx))
}
}

impl<Backing: BackingData> core::fmt::Display for Compartment<Backing> {
impl core::fmt::Display for Compartment {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}

impl<Backing: BackingData> Debug for Compartment<Backing> {
impl Debug for Compartment {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Compartment[{}]", self.name)
}
Expand Down
3 changes: 1 addition & 2 deletions src/runtime/dynlink/src/compartment/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ use tracing::{debug, trace};

use super::Compartment;
use crate::{
library::BackingData,
tls::{TlsInfo, TlsModId, TlsModule, TlsRegion},
DynlinkError, DynlinkErrorKind,
};

impl<Backing: BackingData> Compartment<Backing> {
impl Compartment {
pub(crate) fn insert(&mut self, tm: TlsModule) -> TlsModId {
let prev_gen = self.tls_gen;
self.tls_gen += 1;
Expand Down
67 changes: 30 additions & 37 deletions src/runtime/dynlink/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,44 @@ use std::{collections::HashMap, fmt::Display};

use petgraph::stable_graph::{NodeIndex, StableDiGraph};

use self::engine::ContextEngine;
use crate::{
compartment::{Compartment, CompartmentId},
library::{BackingData, Library, LibraryId, UnloadedLibrary},
engines::ContextEngine,
library::{Library, LibraryId, UnloadedLibrary},
DynlinkError, DynlinkErrorKind,
};

mod deps;
pub mod engine;
mod load;
mod relocate;
pub mod runtime;
mod syms;

#[repr(C)]
/// A dynamic linker context, the main state struct for this crate.
pub struct Context<Engine: ContextEngine> {
pub struct Context {
// Implementation callbacks.
pub(crate) engine: Engine,
pub(crate) engine: Box<dyn ContextEngine + Send>,
// Track all the compartment names.
compartment_names: HashMap<String, usize>,
// Compartments get stable IDs from StableVec.
compartments: Vec<Compartment<Engine::Backing>>,
compartments: Vec<Compartment>,

// This is the primary list of libraries, all libraries have an entry here, and they are
// placed here independent of compartment. Edges denote dependency relationships, and may also
// cross compartments.
pub(crate) library_deps: StableDiGraph<LoadedOrUnloaded<Engine::Backing>, ()>,
pub(crate) library_deps: StableDiGraph<LoadedOrUnloaded, ()>,
}

// Libraries in the dependency graph are placed there before loading, so that they can participate
// in dependency search. So we need to track both kinds of libraries that may be at a given index in
// the graph.
pub enum LoadedOrUnloaded<Backing: BackingData> {
pub enum LoadedOrUnloaded {
Unloaded(UnloadedLibrary),
Loaded(Library<Backing>),
Loaded(Library),
}

impl<Backing: BackingData> Display for LoadedOrUnloaded<Backing> {
impl Display for LoadedOrUnloaded {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LoadedOrUnloaded::Unloaded(unlib) => write!(f, "(unloaded){}", unlib),
Expand All @@ -51,7 +50,7 @@ impl<Backing: BackingData> Display for LoadedOrUnloaded<Backing> {
}
}

impl<Backing: BackingData> LoadedOrUnloaded<Backing> {
impl LoadedOrUnloaded {
/// Get the name of this library, loaded or unloaded.
pub fn name(&self) -> &str {
match self {
Expand All @@ -61,25 +60,25 @@ impl<Backing: BackingData> LoadedOrUnloaded<Backing> {
}

/// Get back a reference to the underlying loaded library, if loaded.
pub fn loaded(&self) -> Option<&Library<Backing>> {
pub fn loaded(&self) -> Option<&Library> {
match self {
LoadedOrUnloaded::Unloaded(_) => None,
LoadedOrUnloaded::Loaded(lib) => Some(lib),
}
}

/// Get back a mutable reference to the underlying loaded library, if loaded.
pub fn loaded_mut(&mut self) -> Option<&mut Library<Backing>> {
pub fn loaded_mut(&mut self) -> Option<&mut Library> {
match self {
LoadedOrUnloaded::Unloaded(_) => None,
LoadedOrUnloaded::Loaded(lib) => Some(lib),
}
}
}

impl<Engine: ContextEngine> Context<Engine> {
impl Context {
/// Construct a new dynamic linker context.
pub fn new(engine: Engine) -> Self {
pub fn new(engine: Box<dyn ContextEngine + Send>) -> Self {
Self {
engine,
compartment_names: HashMap::new(),
Expand All @@ -88,16 +87,17 @@ impl<Engine: ContextEngine> Context<Engine> {
}
}

pub fn replace_engine(&mut self, engine: Box<dyn ContextEngine + Send>) {
self.engine = engine;
}

/// Lookup a compartment by name.
pub fn lookup_compartment(&self, name: &str) -> Option<CompartmentId> {
Some(CompartmentId(*self.compartment_names.get(name)?))
}

/// Get a reference to a compartment back by ID.
pub fn get_compartment(
&self,
id: CompartmentId,
) -> Result<&Compartment<Engine::Backing>, DynlinkError> {
pub fn get_compartment(&self, id: CompartmentId) -> Result<&Compartment, DynlinkError> {
if self.compartments.len() <= id.0 {
return Err(DynlinkErrorKind::InvalidCompartmentId { id }.into());
}
Expand All @@ -108,7 +108,7 @@ impl<Engine: ContextEngine> Context<Engine> {
pub fn get_compartment_mut(
&mut self,
id: CompartmentId,
) -> Result<&mut Compartment<Engine::Backing>, DynlinkError> {
) -> Result<&mut Compartment, DynlinkError> {
if self.compartments.len() <= id.0 {
return Err(DynlinkErrorKind::InvalidCompartmentId { id }.into());
}
Expand All @@ -122,7 +122,7 @@ impl<Engine: ContextEngine> Context<Engine> {
}

/// Get a reference to a library back by ID.
pub fn get_library(&self, id: LibraryId) -> Result<&Library<Engine::Backing>, DynlinkError> {
pub fn get_library(&self, id: LibraryId) -> Result<&Library, DynlinkError> {
if !self.library_deps.contains_node(id.0) {
return Err(DynlinkErrorKind::InvalidLibraryId { id }.into());
}
Expand All @@ -136,10 +136,7 @@ impl<Engine: ContextEngine> Context<Engine> {
}

/// Get a mut reference to a library back by ID.
pub fn get_library_mut(
&mut self,
id: LibraryId,
) -> Result<&mut Library<Engine::Backing>, DynlinkError> {
pub fn get_library_mut(&mut self, id: LibraryId) -> Result<&mut Library, DynlinkError> {
if !self.library_deps.contains_node(id.0) {
return Err(DynlinkErrorKind::InvalidLibraryId { id }.into());
}
Expand All @@ -156,7 +153,7 @@ impl<Engine: ContextEngine> Context<Engine> {
pub fn with_dfs_postorder<R>(
&self,
root_id: LibraryId,
mut f: impl FnMut(&LoadedOrUnloaded<Engine::Backing>) -> R,
mut f: impl FnMut(&LoadedOrUnloaded) -> R,
) -> Vec<R> {
let mut rets = vec![];
let mut visit = petgraph::visit::DfsPostOrder::new(&self.library_deps, root_id.0);
Expand All @@ -172,7 +169,7 @@ impl<Engine: ContextEngine> Context<Engine> {
pub fn with_dfs_postorder_mut<R>(
&mut self,
root_id: LibraryId,
mut f: impl FnMut(&mut LoadedOrUnloaded<Engine::Backing>) -> R,
mut f: impl FnMut(&mut LoadedOrUnloaded) -> R,
) -> Vec<R> {
let mut rets = vec![];
let mut visit = petgraph::visit::DfsPostOrder::new(&self.library_deps, root_id.0);
Expand All @@ -184,19 +181,15 @@ impl<Engine: ContextEngine> Context<Engine> {
}

/// Traverse the library graph with BFS, calling the callback for each library.
pub fn with_bfs(
&self,
root_id: LibraryId,
mut f: impl FnMut(&LoadedOrUnloaded<Engine::Backing>),
) {
pub fn with_bfs(&self, root_id: LibraryId, mut f: impl FnMut(&LoadedOrUnloaded)) {
let mut visit = petgraph::visit::Bfs::new(&self.library_deps, root_id.0);
while let Some(node) = visit.next(&self.library_deps) {
let dep = &self.library_deps[node];
f(dep)
}
}

pub fn libraries(&self) -> LibraryIter<'_, Engine> {
pub fn libraries(&self) -> LibraryIter<'_> {
LibraryIter { ctx: self, next: 0 }
}

Expand All @@ -223,13 +216,13 @@ impl<Engine: ContextEngine> Context<Engine> {
}
}

pub struct LibraryIter<'a, Engine: ContextEngine> {
ctx: &'a Context<Engine>,
pub struct LibraryIter<'a> {
ctx: &'a Context,
next: usize,
}

impl<'a, Engine: ContextEngine> Iterator for LibraryIter<'a, Engine> {
type Item = &'a Library<Engine::Backing>;
impl<'a> Iterator for LibraryIter<'a> {
type Item = &'a Library;

fn next(&mut self) -> Option<Self::Item> {
loop {
Expand Down
Loading

0 comments on commit b80d586

Please sign in to comment.