wasm: Improve API error handling

This commit is contained in:
Luke Street 2025-04-01 21:45:13 -06:00
parent 9b557e4c8e
commit 2bcbc34850
3 changed files with 111 additions and 39 deletions

View File

@ -3,6 +3,7 @@ use alloc::{
rc::{Rc, Weak}, rc::{Rc, Weak},
str::FromStr, str::FromStr,
string::{String, ToString}, string::{String, ToString},
vec,
vec::Vec, vec::Vec,
}; };
use core::cell::RefCell; use core::cell::RefCell;
@ -153,16 +154,17 @@ impl GuestDisplay for Component {
let obj = obj_diff.0.as_ref(); let obj = obj_diff.0.as_ref();
let obj_diff = &obj_diff.1; let obj_diff = &obj_diff.1;
let symbol_idx = symbol_display.symbol as usize; let symbol_idx = symbol_display.symbol as usize;
let symbol = &obj.symbols[symbol_idx]; let Some(symbol) = obj.symbols.get(symbol_idx) else {
return SymbolDisplay { name: "<unknown>".to_string(), ..Default::default() };
};
let symbol_diff = if symbol_display.is_mapping_symbol { let symbol_diff = if symbol_display.is_mapping_symbol {
obj_diff obj_diff
.mapping_symbols .mapping_symbols
.iter() .iter()
.find(|s| s.symbol_index == symbol_idx) .find(|s| s.symbol_index == symbol_idx)
.map(|s| &s.symbol_diff) .map(|s| &s.symbol_diff)
.unwrap()
} else { } else {
&obj_diff.symbols[symbol_idx] obj_diff.symbols.get(symbol_idx)
}; };
SymbolDisplay { SymbolDisplay {
name: symbol.name.clone(), name: symbol.name.clone(),
@ -174,10 +176,10 @@ impl GuestDisplay for Component {
flags: SymbolFlags::from(symbol.flags), flags: SymbolFlags::from(symbol.flags),
align: symbol.align.map(|a| a.get()), align: symbol.align.map(|a| a.get()),
virtual_address: symbol.virtual_address, virtual_address: symbol.virtual_address,
target_symbol: symbol_diff.target_symbol.map(|s| s as u32), target_symbol: symbol_diff.and_then(|sd| sd.target_symbol.map(|s| s as u32)),
match_percent: symbol_diff.match_percent, match_percent: symbol_diff.and_then(|sd| sd.match_percent),
diff_score: symbol_diff.diff_score, diff_score: symbol_diff.and_then(|sd| sd.diff_score),
row_count: symbol_diff.instruction_rows.len() as u32, row_count: symbol_diff.map_or(0, |sd| sd.instruction_rows.len() as u32),
} }
} }
@ -187,7 +189,6 @@ impl GuestDisplay for Component {
row_index: u32, row_index: u32,
diff_config: DiffConfigBorrow, diff_config: DiffConfigBorrow,
) -> InstructionDiffRow { ) -> InstructionDiffRow {
let mut segments = Vec::with_capacity(16);
let obj_diff = diff.get::<ResourceObjectDiff>(); let obj_diff = diff.get::<ResourceObjectDiff>();
let obj = obj_diff.0.as_ref(); let obj = obj_diff.0.as_ref();
let obj_diff = &obj_diff.1; let obj_diff = &obj_diff.1;
@ -198,12 +199,15 @@ impl GuestDisplay for Component {
.iter() .iter()
.find(|s| s.symbol_index == symbol_idx) .find(|s| s.symbol_index == symbol_idx)
.map(|s| &s.symbol_diff) .map(|s| &s.symbol_diff)
.unwrap()
} else { } else {
&obj_diff.symbols[symbol_idx] obj_diff.symbols.get(symbol_idx)
};
let Some(row) = symbol_diff.and_then(|sd| sd.instruction_rows.get(row_index as usize))
else {
return InstructionDiffRow::default();
}; };
let row = &symbol_diff.instruction_rows[row_index as usize];
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow(); let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
let mut segments = Vec::with_capacity(16);
diff::display::display_row(obj, symbol_idx, row, &diff_config, |segment| { diff::display::display_row(obj, symbol_idx, row, &diff_config, |segment| {
segments.push(DiffTextSegment::from(segment)); segments.push(DiffTextSegment::from(segment));
Ok(()) Ok(())
@ -230,9 +234,9 @@ impl GuestDisplay for Component {
) -> Vec<HoverItem> { ) -> Vec<HoverItem> {
let obj_diff = diff.get::<ResourceObjectDiff>(); let obj_diff = diff.get::<ResourceObjectDiff>();
let obj = obj_diff.0.as_ref(); let obj = obj_diff.0.as_ref();
// TODO: colorize replaced/deleted/inserted relocations let addend = 0; // TODO
let override_color = None; let override_color = None; // TODO: colorize replaced/deleted/inserted relocations
diff::display::symbol_hover(obj, symbol_display.symbol as usize, 0, override_color) diff::display::symbol_hover(obj, symbol_display.symbol as usize, addend, override_color)
.into_iter() .into_iter()
.map(|item| HoverItem::from(item)) .map(|item| HoverItem::from(item))
.collect() .collect()
@ -243,7 +247,7 @@ impl GuestDisplay for Component {
symbol_display: SectionDisplaySymbol, symbol_display: SectionDisplaySymbol,
row_index: u32, row_index: u32,
diff_config: DiffConfigBorrow, diff_config: DiffConfigBorrow,
) -> Result<Vec<ContextItem>, String> { ) -> Vec<ContextItem> {
let obj_diff = diff.get::<ResourceObjectDiff>(); let obj_diff = diff.get::<ResourceObjectDiff>();
let obj = obj_diff.0.as_ref(); let obj = obj_diff.0.as_ref();
let obj_diff = &obj_diff.1; let obj_diff = &obj_diff.1;
@ -254,24 +258,35 @@ impl GuestDisplay for Component {
.iter() .iter()
.find(|s| s.symbol_index == symbol_idx) .find(|s| s.symbol_index == symbol_idx)
.map(|s| &s.symbol_diff) .map(|s| &s.symbol_diff)
.unwrap()
} else { } else {
&obj_diff.symbols[symbol_idx] obj_diff.symbols.get(symbol_idx)
}; };
let row = &symbol_diff.instruction_rows[row_index as usize]; let Some(ins_ref) = symbol_diff
let Some(ins_ref) = row.ins_ref else { .and_then(|sd| sd.instruction_rows.get(row_index as usize))
return Ok(Vec::new()); .and_then(|row| row.ins_ref)
else {
return Vec::new();
}; };
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow(); let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else { let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else {
return Err("Failed to resolve instruction".into()); return vec![ContextItem::Copy(ContextItemCopy {
value: "Failed to resolve instruction".to_string(),
label: Some("error".to_string()),
})];
}; };
let ins = let ins = match obj.arch.process_instruction(resolved, &diff_config) {
obj.arch.process_instruction(resolved, &diff_config).map_err(|e| e.to_string())?; Ok(ins) => ins,
Ok(diff::display::instruction_context(obj, resolved, &ins) Err(e) => {
return vec![ContextItem::Copy(ContextItemCopy {
value: e.to_string(),
label: Some("error".to_string()),
})];
}
};
diff::display::instruction_context(obj, resolved, &ins)
.into_iter() .into_iter()
.map(|item| ContextItem::from(item)) .map(|item| ContextItem::from(item))
.collect()) .collect()
} }
fn instruction_hover( fn instruction_hover(
@ -279,7 +294,7 @@ impl GuestDisplay for Component {
symbol_display: SectionDisplaySymbol, symbol_display: SectionDisplaySymbol,
row_index: u32, row_index: u32,
diff_config: DiffConfigBorrow, diff_config: DiffConfigBorrow,
) -> Result<Vec<HoverItem>, String> { ) -> Vec<HoverItem> {
let obj_diff = diff.get::<ResourceObjectDiff>(); let obj_diff = diff.get::<ResourceObjectDiff>();
let obj = obj_diff.0.as_ref(); let obj = obj_diff.0.as_ref();
let obj_diff = &obj_diff.1; let obj_diff = &obj_diff.1;
@ -290,24 +305,37 @@ impl GuestDisplay for Component {
.iter() .iter()
.find(|s| s.symbol_index == symbol_idx) .find(|s| s.symbol_index == symbol_idx)
.map(|s| &s.symbol_diff) .map(|s| &s.symbol_diff)
.unwrap()
} else { } else {
&obj_diff.symbols[symbol_idx] obj_diff.symbols.get(symbol_idx)
}; };
let row = &symbol_diff.instruction_rows[row_index as usize]; let Some(ins_ref) = symbol_diff
let Some(ins_ref) = row.ins_ref else { .and_then(|sd| sd.instruction_rows.get(row_index as usize))
return Ok(Vec::new()); .and_then(|row| row.ins_ref)
else {
return Vec::new();
}; };
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow(); let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else { let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else {
return Err("Failed to resolve instruction".into()); return vec![HoverItem::Text(HoverItemText {
label: "Error".to_string(),
value: "Failed to resolve instruction".to_string(),
color: HoverItemColor::Delete,
})];
}; };
let ins = let ins = match obj.arch.process_instruction(resolved, &diff_config) {
obj.arch.process_instruction(resolved, &diff_config).map_err(|e| e.to_string())?; Ok(ins) => ins,
Ok(diff::display::instruction_hover(obj, resolved, &ins) Err(e) => {
return vec![HoverItem::Text(HoverItemText {
label: "Error".to_string(),
value: e.to_string(),
color: HoverItemColor::Delete,
})];
}
};
diff::display::instruction_hover(obj, resolved, &ins)
.into_iter() .into_iter()
.map(|item| HoverItem::from(item)) .map(|item| HoverItem::from(item))
.collect()) .collect()
} }
} }
@ -536,4 +564,40 @@ impl From<diff::display::SymbolNavigationKind> for SymbolNavigationKind {
} }
} }
impl Default for InstructionDiffKind {
fn default() -> Self { Self::None }
}
impl Default for InstructionDiffRow {
fn default() -> Self { Self { segments: Default::default(), diff_kind: Default::default() } }
}
impl Default for SymbolKind {
fn default() -> Self { Self::Unknown }
}
impl Default for SymbolFlags {
fn default() -> Self { Self::empty() }
}
impl Default for SymbolDisplay {
fn default() -> Self {
Self {
name: Default::default(),
demangled_name: Default::default(),
address: Default::default(),
size: Default::default(),
kind: Default::default(),
section: Default::default(),
flags: Default::default(),
align: Default::default(),
virtual_address: Default::default(),
target_symbol: Default::default(),
match_percent: Default::default(),
diff_score: Default::default(),
row_count: Default::default(),
}
}
}
export!(Component); export!(Component);

View File

@ -35,9 +35,17 @@ static FORCE_CODEGEN_OF_CABI_REALLOC: unsafe extern "C" fn(
pub unsafe extern "C" fn cabi_realloc( pub unsafe extern "C" fn cabi_realloc(
old_ptr: *mut u8, old_ptr: *mut u8,
old_len: usize, old_len: usize,
align: usize, mut align: usize,
new_len: usize, new_len: usize,
) -> *mut u8 { ) -> *mut u8 {
// HACK: The object crate requires the data alignment for 64-bit objects to be 8,
// but in wasm32, our allocator will have a minimum alignment of 4. We can't specify
// the alignment of `list<u8>` in the component model, so we work around this here.
// https://github.com/WebAssembly/component-model/issues/258
#[cfg(target_pointer_width = "32")]
if align == 1 {
align = 8;
}
let layout; let layout;
let ptr = if old_len == 0 { let ptr = if old_len == 0 {
if new_len == 0 { if new_len == 0 {

View File

@ -257,14 +257,14 @@ interface display {
symbol: section-display-symbol, symbol: section-display-symbol,
row-index: u32, row-index: u32,
config: borrow<diff-config>, config: borrow<diff-config>,
) -> result<list<context-item>, string>; ) -> list<context-item>;
instruction-hover: func( instruction-hover: func(
diff: borrow<object-diff>, diff: borrow<object-diff>,
symbol: section-display-symbol, symbol: section-display-symbol,
row-index: u32, row-index: u32,
config: borrow<diff-config>, config: borrow<diff-config>,
) -> result<list<hover-item>, string>; ) -> list<hover-item>;
} }
world api { world api {