Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions cmd/monorail/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -939,11 +939,8 @@ fn monorail_mac_table(
if let Ok(r) = r {
let s = r.as_struct()?;
assert_eq!(s.name(), "MacTableEntry");
let port = s["port"].as_base().unwrap().as_u16().unwrap();
let mut mac = [0; 6];
for (i, m) in s["mac"].as_array().unwrap().iter().enumerate() {
mac[i] = m.as_base().unwrap().as_u8().unwrap()
}
let port = s.field::<u16>("port").unwrap();
let mac = s.field::<[u8; 6]>("mac").unwrap();
if mac == [0; 6] && port == 0xFFFF {
println!("Skipping empty MAC address");
} else {
Expand Down
79 changes: 32 additions & 47 deletions cmd/net/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,7 @@ fn net_ip(
};
let v = v.as_tuple()?;
assert_eq!(v.name(), "MacAddress");
let mut mac = [0; 6];
for (i, byte) in v[0].as_array()?.iter().enumerate() {
mac[i] = byte.as_base()?.as_u8().unwrap();
}
let mac = v.field::<[u8; 6]>(0)?;
print!("{}: ", "MAC address".bold());
for (i, byte) in mac.iter().enumerate() {
if i > 0 {
Expand Down Expand Up @@ -227,11 +224,8 @@ fn net_mac_table(
if let Ok(r) = r {
let s = r.as_struct()?;
assert_eq!(s.name(), "KszMacTableEntry");
let port = s["port"].as_base().unwrap().as_u16().unwrap();
let mut mac = [0; 6];
for (i, m) in s["mac"].as_array().unwrap().iter().enumerate() {
mac[i] = m.as_base().unwrap().as_u8().unwrap()
}
let port = s.field::<u16>("port")?;
let mac = s.field::<[u8; 6]>("mac")?;
Comment thread
mkeeter marked this conversation as resolved.
if mac == [0; 6] && port == 0xFFFF {
humility::msg!("Skipping empty MAC address");
} else {
Expand Down Expand Up @@ -290,16 +284,9 @@ fn net_status(
let s = v.as_struct()?;
assert_eq!(s.name(), "ManagementLinkStatus");

let to_bool_vec = |name| -> Result<Vec<bool>> {
Ok(s[name]
.as_array()?
.iter()
.map(|i| i.as_base().unwrap().as_bool().unwrap())
.collect())
};
let ksz_100base_fx = to_bool_vec("ksz8463_100base_fx_link_up")?;
let vsc_100base_fx = to_bool_vec("vsc85x2_100base_fx_link_up")?;
let vsc_sgmii = to_bool_vec("vsc85x2_sgmii_link_up")?;
let ksz_100base_fx: Vec<bool> = s.field("ksz8463_100base_fx_link_up")?;
let vsc_100base_fx: Vec<bool> = s.field("vsc85x2_100base_fx_link_up")?;
let vsc_sgmii: Vec<bool> = s.field("vsc85x2_sgmii_link_up")?;

let up_down = |b| {
if b { " UP ".green() } else { "DOWN".red() }
Expand Down Expand Up @@ -382,10 +369,10 @@ fn net_counters(
}

fn net_counters_table(s: &Struct) -> Result<()> {
let k_tx = s["ksz8463_tx"].as_array()?;
let k_rx = s["ksz8463_rx"].as_array()?;
let k_tx = s.field::<[_; 3]>("ksz8463_tx")?;
let k_rx = s.field::<[_; 3]>("ksz8463_rx")?;
let value = |k: &Struct, s: &str| {
let k = k[s].as_base().unwrap().as_u32().unwrap();
let k = k.field::<u32>(s).unwrap();
let out = format!("{:>6}", k);
if k > 0 {
if s.contains("ERR") { out.red() } else { out.green() }
Expand All @@ -407,8 +394,8 @@ fn net_counters_table(s: &Struct) -> Result<()> {
" |-----------|--------|--------|--------|--------|--------|--------|"
);
for i in 0..3 {
let k_tx = k_tx[i].as_struct()?;
let k_rx = k_rx[i].as_struct()?;
let k_tx = &k_tx[i];
let k_rx = &k_rx[i];
println!(
" | Port {} | {} | {} | {} | {} | {} | {} |",
i + 1,
Expand All @@ -426,12 +413,12 @@ fn net_counters_table(s: &Struct) -> Result<()> {

println!();

let v_tx = s["vsc85x2_tx"].as_array()?;
let v_rx = s["vsc85x2_rx"].as_array()?;
let v_mac_valid = s["vsc85x2_mac_valid"].as_base()?.as_bool().unwrap();
let v_tx = s.field::<[_; 2]>("vsc85x2_tx")?;
let v_rx = s.field::<[_; 2]>("vsc85x2_rx")?;
let v_mac_valid = s.field::<bool>("vsc85x2_mac_valid")?;

let value = |v: &Struct, s: &str| {
let v = v[s].as_base().unwrap().as_u16().unwrap();
let v = v.field::<u16>(s).unwrap();
let out = format!("{:>6}", v);
if v > 0 {
if s.contains("good") { out.green() } else { out.red() }
Expand All @@ -447,8 +434,8 @@ fn net_counters_table(s: &Struct) -> Result<()> {
println!(" | | Good | Bad | Good | Bad |");
println!(" |-----------------------------------------------------|");
for i in 0..2 {
let v_tx = v_tx[i].as_struct()?;
let v_rx = v_rx[i].as_struct()?;
let v_tx = &v_tx[i];
let v_rx = &v_rx[i];
if v_mac_valid {
println!(
" | Port {} | MAC | {} | {} | {} | {} |",
Expand Down Expand Up @@ -479,39 +466,37 @@ fn net_counters_table(s: &Struct) -> Result<()> {
}

fn net_counters_diagram(s: &Struct) -> Result<()> {
let k_tx = s["ksz8463_tx"].as_array()?;
let k_rx = s["ksz8463_rx"].as_array()?;
let value = |k: &Struct, s: &str| k[s].as_base().unwrap().as_u32().unwrap();
let k_tx = s.field::<[Struct; 3]>("ksz8463_tx")?;
let k_rx = s.field::<[Struct; 3]>("ksz8463_rx")?;

let mut ksz_tx = [0; 3];
let mut ksz_rx = [0; 3];
for port in 0..3 {
let k_tx = k_tx[port].as_struct()?;
let k_rx = k_rx[port].as_struct()?;
let k_tx = &k_tx[port];
let k_rx = &k_rx[port];
for t in ["unicast", "broadcast", "multicast"] {
ksz_tx[port] += value(k_tx, t);
ksz_rx[port] += value(k_rx, t);
ksz_tx[port] += k_tx.field::<u32>(t)?;
ksz_rx[port] += k_rx.field::<u32>(t)?;
}
}

let v_tx = s["vsc85x2_tx"].as_array()?;
let v_rx = s["vsc85x2_rx"].as_array()?;
let v_mac_valid = s["vsc85x2_mac_valid"].as_base()?.as_bool().unwrap();
let value = |v: &Struct, s: &str| v[s].as_base().unwrap().as_u16().unwrap();
let v_tx = s.field::<[Struct; 2]>("vsc85x2_tx")?;
let v_rx = s.field::<[Struct; 2]>("vsc85x2_rx")?;
let v_mac_valid = s.field::<bool>("vsc85x2_mac_valid")?;

let mut v_mac_tx = [0; 2];
let mut v_mac_rx = [0; 2];
let mut v_media_tx = [0; 2];
let mut v_media_rx = [0; 2];
for port in 0..2 {
let v_tx = v_tx[port].as_struct()?;
let v_rx = v_rx[port].as_struct()?;
let v_tx = &v_tx[port];
let v_rx = &v_rx[port];
if v_mac_valid {
v_mac_tx[port] = value(v_tx, "mac_good");
v_mac_rx[port] = value(v_rx, "mac_good");
v_mac_tx[port] = v_tx.field::<u16>("mac_good")?;
v_mac_rx[port] = v_rx.field::<u16>("mac_good")?;
}
v_media_tx[port] = value(v_tx, "media_good");
v_media_rx[port] = value(v_rx, "media_good");
v_media_tx[port] = v_tx.field::<u16>("media_good")?;
v_media_rx[port] = v_rx.field::<u16>("media_good")?;
}

let mac = |i: u16| {
Expand Down
15 changes: 5 additions & 10 deletions cmd/tasks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,18 +565,13 @@ fn stack_guess<'a>(
let reflect::Value::Struct(s) = &task_value else {
bail!("invalid type for task_value")
};
let Some(reflect::Value::Struct(save)) = s.get("save") else {
bail!("invalid type for save")
};
let Some(reflect::Value::Base(reflect::Base::U32(addr))) = save.get("r7")
else {
bail!("invalid type for r7")
};
let pc = core.read_word_32(*addr + 4)? & !1;
let save = s.field::<reflect::Struct>("save")?;
let addr = save.field::<u32>("r7")?;
let pc = core.read_word_32(addr + 4)? & !1;

let mut regs = BTreeMap::new();
regs.insert(ARMRegister::R7, *addr);
regs.insert(ARMRegister::LR, *addr);
regs.insert(ARMRegister::R7, addr);
regs.insert(ARMRegister::LR, addr);

// Provide a dummy stack value to pick the
// correct memory region
Expand Down
121 changes: 91 additions & 30 deletions humility-core/src/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,29 +137,13 @@ impl Value {
for f in f.split(".") {
match v {
Value::Struct(s) => {
v = s.get(f).ok_or_else(|| {
anyhow!(
"could not field field `{f}`; \
available fields are {:?}",
s.members
.keys()
.map(|s| s.as_str())
.collect::<Vec<_>>()
.join(", ")
)
})?;
v = s.get(f)?;
}
Value::Tuple(t) => {
let index: usize = f.parse().with_context(|| {
format!("could not parse tuple index from `{f}`")
})?;
v = t.1.get(index).ok_or_else(|| {
anyhow!(
"could not get field {index} from tuple \
with {} elements",
t.1.len()
)
})?;
v = t.get(index)?;
}
_ => bail!(
"expected a struct or tuple when getting field `{f}`, \
Expand Down Expand Up @@ -490,7 +474,7 @@ impl Format for Base {
#[derive(Clone, Debug, Default)]
pub struct Struct {
name: String,
members: IndexMap<String, Box<Value>>,
members: IndexMap<String, Value>,
}

impl Struct {
Expand All @@ -507,7 +491,7 @@ impl Struct {
}

pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
self.members.iter().map(|(s, v)| (s.as_str(), &**v))
self.members.iter().map(|(s, v)| (s.as_str(), v))
}

/// Verifies that the struct contains _at least_ members with the given
Expand All @@ -521,13 +505,35 @@ impl Struct {
Ok(())
}

/// Returns a reference to the value of the member named `name`, if it
/// exists, or `None`, if no member with that name exists.
pub fn get<Q>(&self, name: &Q) -> Option<&Value>
/// Returns a reference to the value of the member named `name`
///
/// If the name is not found, then an informative error is returned.
pub fn get<Q>(&self, name: &Q) -> Result<&Value>
where
Q: std::hash::Hash + indexmap::Equivalent<String> + ?Sized,
Q: std::hash::Hash
+ indexmap::Equivalent<String>
+ ?Sized
+ std::fmt::Display,
{
self.members.get(name).map(Box::as_ref)
self.members.get(name).ok_or_else(|| {
anyhow!(
"could not find field `{}` in struct `{}`; \
available fields are {:?}",
name,
self.name,
self.members
.keys()
.map(|s| s.as_str())
.collect::<Vec<_>>()
.join(", ")
)
})
}

/// Loads the field with name `name` if it exists
pub fn field<T: Load>(&self, name: &str) -> Result<T> {
let v = self.get(name)?;
T::from_value(v)
}
}

Expand Down Expand Up @@ -592,6 +598,25 @@ impl Tuple {
pub fn name(&self) -> &str {
self.0.as_str()
}

/// Returns a reference to a value in the tuple, by index
pub fn get(&self, index: usize) -> Result<&Value> {
let Some(v) = self.1.get(index) else {
bail!(
"could not get field {} in tuple `{}` with {} elements",
index,
self.0,
self.1.len()
);
};
Ok(v)
}

/// Loads the field with index `i` if it exists
pub fn field<T: Load>(&self, index: usize) -> Result<T> {
let v = self.get(index)?;
T::from_value(v)
Comment thread
mkeeter marked this conversation as resolved.
}
}

/// Allows the tuple to be treated like a slice, e.g. with `len()` and indexing.
Expand Down Expand Up @@ -903,10 +928,7 @@ pub fn load_struct(
for m in &ty.members {
let maddr = addr + m.offset;
let mty = hubris.lookup_type(m.goff)?;
s.members.insert(
m.name.clone(),
Box::new(load_value(hubris, buf, mty, maddr)?),
);
s.members.insert(m.name.clone(), load_value(hubris, buf, mty, maddr)?);
}

Ok(s)
Expand Down Expand Up @@ -1035,6 +1057,36 @@ impl Load for Enum {
}
}

impl Load for Struct {
fn from_value(v: &Value) -> Result<Self> {
if let Value::Struct(v) = v {
Ok(v.clone())
} else {
bail!("expected struct, got {v:?}");
}
}
}

impl Load for Tuple {
fn from_value(v: &Value) -> Result<Self> {
if let Value::Tuple(v) = v {
Ok(v.clone())
} else {
bail!("expected tuple, got {v:?}");
}
}
}

impl Load for Base {
fn from_value(v: &Value) -> Result<Self> {
if let Value::Base(v) = v {
Ok(v.clone())
} else {
bail!("expected base, got {v:?}");
}
}
}

impl Load for bool {
fn from_value(v: &Value) -> Result<Self> {
v.as_base()?.as_bool().ok_or_else(|| anyhow!("not a bool: {:?}", v))
Expand Down Expand Up @@ -1071,6 +1123,15 @@ impl Load for f32 {
}
}

impl Load for () {
fn from_value(v: &Value) -> Result<Self> {
match v.as_base()? {
Base::U0 => Ok(()),
b => bail!("expected U0, got base {b:?}"),
}
}
}

impl Load for Array {
fn from_value(v: &Value) -> Result<Self> {
if let Value::Array(v) = v {
Expand Down Expand Up @@ -1236,7 +1297,7 @@ fn deserialize_struct<'a>(
for m in &ty.members {
let mty = hubris.lookup_type(m.goff)?;
let out = deserialize_value(hubris, buf, mty)?;
s.members.insert(m.name.clone(), Box::new(out.0));
s.members.insert(m.name.clone(), out.0);
buf = out.1;
}

Expand Down
Loading
Loading