From 6e49d36d614d7c19c3f406b2ea1c2aae6ba6248f Mon Sep 17 00:00:00 2001 From: Mikhael Skvortsov Date: Wed, 15 Mar 2023 14:50:54 +0300 Subject: [PATCH 1/6] disasm: add ability to disasm a fragment --- Cargo.lock | 2 +- Cargo.toml | 4 +- src/disasm/codedict.rs | 166 ++++++++++++++ src/disasm/commands.rs | 24 +- src/disasm/fmt.rs | 228 +++++++++++++++++++ src/disasm/loader.rs | 496 ++++++++++------------------------------- src/disasm/mod.rs | 2 + src/disasm/tests.rs | 22 ++ src/disasm/types.rs | 27 ++- src/main.rs | 5 + 10 files changed, 588 insertions(+), 388 deletions(-) create mode 100644 src/disasm/codedict.rs create mode 100644 src/disasm/fmt.rs diff --git a/Cargo.lock b/Cargo.lock index fda5f893..50c5ee41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1325,7 +1325,7 @@ dependencies = [ [[package]] name = "tvm_linker" -version = "0.19.5" +version = "0.19.6" dependencies = [ "assert_cmd", "base64 0.13.1", diff --git a/Cargo.toml b/Cargo.toml index ce261606..6c4d172e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license-file = 'LICENSE.md' name = 'tvm_linker' readme = 'README.md' repository = 'https://github.com/tonlabs/TVM-linker' -version = '0.19.5' +version = '0.19.6' [[bin]] name = 'tvm_linker' @@ -48,4 +48,4 @@ similar = '2.2.0' [lib] name = 'ton_utils' path = 'src/lib.rs' - +test = false diff --git a/src/disasm/codedict.rs b/src/disasm/codedict.rs new file mode 100644 index 00000000..12e50d0c --- /dev/null +++ b/src/disasm/codedict.rs @@ -0,0 +1,166 @@ +/* + * Copyright 2023 TON DEV SOLUTIONS LTD. + * + * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use + * this file except in compliance with the License. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific TON DEV software governing permissions and + * limitations under the License. + */ + +use std::collections::HashMap; +use ton_types::{Cell, HashmapE, HashmapType, Result, SliceData, fail}; +use super::{ + types::{Instruction, InstructionParameter, Code}, + loader::Loader, fmt::print_code +}; + +fn match_dictpushconst_dictugetjmp(pair: &mut [Instruction]) -> Option<&mut Vec> { + let insn2 = pair.get(1)?.name(); + if insn2 != "DICTUGETJMP" { + return None + } + let insn1 = pair.get_mut(0)?; + if insn1.name() != "DICTPUSHCONST" && insn1.name() != "PFXDICTSWITCH" { + return None + } + Some(insn1.params_mut()) +} + +fn process_dictpushconst_dictugetjmp(code: &mut Code) { + for pair in code.chunks_mut(2) { + if let Some(params) = match_dictpushconst_dictugetjmp(pair) { + // TODO transform cell to code right here (for nested dicts) + params.push(InstructionParameter::CodeDictMarker) + } + } +} + +fn traverse_code_tree(code: &mut Code, process: fn(&mut Code)) { + let mut stack = vec!(code); + while let Some(code) = stack.pop() { + process(code); + for insn in code { + for param in insn.params_mut() { + match param { + InstructionParameter::Code { code: ref mut inner, cell: _ } => stack.push(inner), + _ => () + } + } + } + } +} + +pub fn elaborate_dictpushconst_dictugetjmp(code: &mut Code) { + traverse_code_tree(code, process_dictpushconst_dictugetjmp) +} + +pub(super) struct DelimitedHashmapE { + dict: HashmapE, + map: HashMap, (u64, usize, Code)>, +} + +impl DelimitedHashmapE { + pub fn new(cell: Cell, key_size: usize) -> Self { + Self { + dict: HashmapE::with_hashmap(key_size, Some(cell)), + map: HashMap::new(), + } + } + fn slice_eq_data(lhs: &SliceData, rhs: &SliceData) -> bool { + let bit_len = lhs.remaining_bits(); + if bit_len != rhs.remaining_bits() { + return false; + } + let mut offset = 0; + while (offset + 8) <= bit_len { + if lhs.get_byte(offset).unwrap() != rhs.get_byte(offset).unwrap() { + return false; + } + offset += 8 + } + if (bit_len > offset) && (lhs.get_bits(offset, bit_len - offset).unwrap() != rhs.get_bits(offset, bit_len - offset).unwrap()) { + return false; + } + true + } + fn slice_eq_children(lhs: &SliceData, rhs: &SliceData) -> bool { + let refs_count = lhs.remaining_references(); + if refs_count != rhs.remaining_references() { + return false; + } + for i in 0..refs_count { + let ref1 = lhs.reference(i).unwrap(); + let ref2 = rhs.reference(i).unwrap(); + if ref1.repr_hash() != ref2.repr_hash() { + return false; + } + } + true + } + fn locate(mut slice: SliceData, target: &SliceData, path: Vec) -> Result<(Vec, usize)> { + if Self::slice_eq_children(&slice, target) { + loop { + if Self::slice_eq_data(&slice, target) { + return Ok((path, slice.pos())) + } + if slice.get_next_bit().is_err() { + break + } + } + } + for i in 0..slice.remaining_references() { + let child = SliceData::load_cell(slice.reference(i)?)?; + let mut next = path.clone(); + next.push(i as u8); + if let Ok(v) = Self::locate(child, target, next) { + return Ok(v) + } + } + fail!("not found") + } + pub fn mark(&mut self) -> Result<()> { + let dict_slice = SliceData::load_cell_ref(self.dict.data().unwrap())?; + for entry in self.dict.iter() { + let (key, mut slice) = entry?; + let id = SliceData::load_builder(key)?.get_next_int(self.dict.bit_len())?; + let loc = Self::locate(dict_slice.clone(), &slice, vec!())?; + let mut loader = Loader::new(false); + let code = loader.load(&mut slice, true)?; + if self.map.insert(loc.0, (id, loc.1, code)).is_some() { + fail!("non-unique path found") + } + } + Ok(()) + } + fn print_impl(&self, cell: &Cell, indent: &str, path: Vec) -> String { + let mut text = String::new(); + text += &format!("{}.cell ", indent); + text += &format!("{{ ;; #{}\n", cell.repr_hash().to_hex_string()); + let inner_indent = String::from(" ") + indent; + let mut slice = SliceData::load_cell_ref(cell).unwrap(); + if let Some((id, offset, code)) = self.map.get(&path) { + let aux = slice.get_next_slice(*offset).unwrap(); + text += &format!("{}.blob x{}\n", inner_indent, aux.to_hex_string()); + text += &format!("{};; method {}\n", inner_indent, id); + text += &print_code(code, &inner_indent, true, 0); + } else { + if slice.remaining_bits() > 0 { + text += &format!("{}.blob x{}\n", inner_indent, slice.to_hex_string()); + } + for i in 0..cell.references_count() { + let mut path = path.clone(); + path.push(i as u8); + text += &self.print_impl(&cell.reference(i).unwrap(), inner_indent.as_str(), path); + } + } + text += &format!("{}}}\n", indent); + text + } + pub fn print(&self, indent: &str) -> String { + self.print_impl(self.dict.data().unwrap(), indent, vec!()) + } +} diff --git a/src/disasm/commands.rs b/src/disasm/commands.rs index 2b34d456..1b82c09a 100644 --- a/src/disasm/commands.rs +++ b/src/disasm/commands.rs @@ -20,8 +20,12 @@ use ton_types::cells_serialization::deserialize_cells_tree; use ton_types::{Cell, HashmapE, HashmapType, SliceData, UInt256, Status}; use std::io::Cursor; -use super::types::Shape; -use super::loader::{Loader, print_code, elaborate_dictpushconst_dictugetjmp}; +use super::{ + codedict::elaborate_dictpushconst_dictugetjmp, + fmt::print_code, + loader::Loader, + types::Shape, +}; pub fn disasm_command(m: &ArgMatches) -> Status { if let Some(m) = m.subcommand_matches("dump") { @@ -30,6 +34,8 @@ pub fn disasm_command(m: &ArgMatches) -> Status { return disasm_graphviz_command(m); } else if let Some(m) = m.subcommand_matches("text") { return disasm_text_command(m); + } else if let Some(m) = m.subcommand_matches("fragment") { + return disasm_fragment_command(m); } bail!("unknown command") } @@ -305,6 +311,18 @@ fn disasm_text_command(m: &ArgMatches) -> Status { Ok(()) } +fn disasm_fragment_command(m: &ArgMatches) -> Status { + let fragment = m.value_of("FRAGMENT").unwrap(); + let mut slice = SliceData::from_string(fragment)?; + + let mut loader = Loader::new(false); + let code = loader.load(&mut slice, false).unwrap(); + let text = print_code(&code, "", true, 12); + + print!("{}", text); + Ok(()) +} + pub(super) fn disasm(slice: &mut SliceData) -> String { disasm_ex(slice, false) } @@ -313,5 +331,5 @@ pub(super) fn disasm_ex(slice: &mut SliceData, collapsed: bool) -> String { let mut loader = Loader::new(collapsed); let mut code = loader.load(slice, false).unwrap(); elaborate_dictpushconst_dictugetjmp(&mut code); - print_code(&code, "") + print_code(&code, "", true, 0) } diff --git a/src/disasm/fmt.rs b/src/disasm/fmt.rs new file mode 100644 index 00000000..f8e19d15 --- /dev/null +++ b/src/disasm/fmt.rs @@ -0,0 +1,228 @@ +/* + * Copyright 2023 TON DEV SOLUTIONS LTD. + * + * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use + * this file except in compliance with the License. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific TON DEV software governing permissions and + * limitations under the License. + */ + +use ton_types::{Cell, Result, SliceData}; +use super::{ + types::{Instruction, InstructionParameter, Code}, + codedict::DelimitedHashmapE +}; + +fn print_code_dict(cell: &Cell, key_size: usize, indent: &str) -> Result { + let mut map = DelimitedHashmapE::new(cell.clone(), key_size); + map.mark()?; + Ok(map.print(indent)) +} + +fn print_dictpushconst(insn: &Instruction, indent: &str) -> String { + let key_length = if let Some(InstructionParameter::Length(l)) = insn.params().get(0) { + *l + } else { + unreachable!() + }; + let cell = if let Some(InstructionParameter::Cell { cell, collapsed }) = insn.params().get(1) { + assert!(collapsed == &false); + cell.as_ref() + } else { + unreachable!() + }; + if let Some(cell) = cell { + let text = if let Some(InstructionParameter::CodeDictMarker) = insn.params().get(2) { + print_code_dict(cell, key_length, indent) + .unwrap_or_else(|_| print_cell(cell, indent, true)) + } else { + print_cell(cell, indent, true) + }; + format!("{} {}\n{}", insn.name(), key_length, text) + } else { + format!("{} {} ;; missing dict ref\n", insn.name(), key_length) + } +} + +fn print_cell(cell: &Cell, indent: &str, dot_cell: bool) -> String { + let mut text = String::new(); + if dot_cell { + text += &format!("{}.cell ", indent); + } + text += &format!("{{ ;; #{}\n", cell.repr_hash().to_hex_string()); + let inner_indent = String::from(" ") + indent; + if cell.bit_length() > 0 { + text += &format!("{}.blob x{}\n", inner_indent, cell.to_hex_string(true)); + } + let refs = cell.references_count(); + for i in 0..refs { + text += &print_cell(&cell.reference(i).unwrap(), &inner_indent, true); + } + text += &format!("{}}}", indent); + if dot_cell { + text += "\n"; + } + text +} + +fn truncate(s: String, n: usize) -> String { + match s.char_indices().nth(n) { + None => s, + Some((idx, _)) => String::from(&s[..idx]), + } +} + +fn print_bytecode(slice: Option<(&SliceData, usize)>, bytecode_width: usize) -> String { + let mut text = String::new(); + if bytecode_width > 0 { + let mut bytecode = String::new(); + if let Some((slice, refs)) = slice { + let mut b = slice.to_hex_string(); + if refs > 0 { + b += &format!(" {{{}r}}", refs); + } + bytecode = truncate(b, bytecode_width); + } + text += &format!("{: String { + let mut text = String::new(); + for insn in code { + text += &print_bytecode(insn.bytecode().map(|v| (v, insn.refs())), bytecode_width); + text += indent; + if full { + match insn.name() { + "DICTPUSHCONST" | "PFXDICTSWITCH" => { + // TODO better improve assembler for these two insns + text += &print_dictpushconst(insn, indent); + continue + } + "IMPLICIT-JMP" => { + if let Some(InstructionParameter::Code { code, cell }) = insn.params().get(0) { + let hash = cell.as_ref().unwrap().repr_hash().to_hex_string(); + text += &format!(".cell {{ ;; #{}\n", hash); + let inner_indent = String::from(" ") + indent; + text += &print_code(code, &inner_indent, full, bytecode_width); + text += indent; + text += "}\n"; + } else { + unreachable!() + } + continue + } + _ => () + } + } + text += insn.name(); + if insn.is_quiet() { + text += "Q"; + } + text += &print_insn_params(insn.params(), indent, full, bytecode_width); + if let Some(comment) = insn.comment() { + text += &format!(" ;; {}", comment); + } + text += "\n"; + } + text +} + +fn print_insn_params(params: &Vec, indent: &str, full: bool, bytecode_width: usize) -> String { + use InstructionParameter::*; + + let mut text = String::new(); + let len = params.len(); + if len > 0 { + text += " "; + } + for (index, param) in params.iter().enumerate() { + let last = len == (index + 1); + let mut curr_is_block = false; + match param { + BigInteger(i) => { + text += &format!("{}", i); + } + ControlRegister(c) => { + text += &format!("c{}", c); + } + Integer(i) => { + text += &format!("{}", i); + } + Length(l) => { + text += &format!("{}", l); + } + LengthAndIndex(l, i) => { + text += &format!("{}, {}", l, i); + } + Nargs(n) => { + text += &format!("{}", n); + } + Pargs(p) => { + text += &format!("{}", p); + } + Rargs(r) => { + text += &format!("{}", r); + } + Slice(s) => { + // TODO slice may have references + assert!(s.remaining_references() == 0); + text += &format!("x{}", s.to_hex_string()); + } + StackRegister(r) => { + text += &format!("s{}", r); + } + StackRegisterPair(ra, rb) => { + text += &format!("s{}, s{}", ra, rb); + } + StackRegisterTriple(ra, rb, rc) => { + text += &format!("s{}, s{}, s{}", ra, rb, rc); + } + Code { code, cell } => { + if full { + if let Some(cell) = cell { + text += &format!("{{ ;; #{}\n", cell.repr_hash().to_hex_string()); + } else { + text += "{\n"; + } + let inner_indent = String::from(" ") + indent; + text += &print_code(code, &inner_indent, full, bytecode_width); + text += &print_bytecode(None, bytecode_width); + text += indent; + text += "}"; + curr_is_block = true; + } + } + Cell { cell, collapsed } => { + if full { + if *collapsed { + text += ""; + } else if let Some(cell) = cell { + text += &print_cell(cell, indent, false); + } else { + text += "{\n"; + text += &print_bytecode(None, bytecode_width); + text += &format!("{} ;; missing cell\n", indent); + text += &print_bytecode(None, bytecode_width); + text += indent; + text += "}"; + } + curr_is_block = true; + } + } + CodeDictMarker => { + // markers must have been already eliminated + unreachable!() + } + } + if !last && !curr_is_block { + text += ", "; + } + } + text +} diff --git a/src/disasm/loader.rs b/src/disasm/loader.rs index 81f4618f..6158dbd6 100644 --- a/src/disasm/loader.rs +++ b/src/disasm/loader.rs @@ -11,7 +11,7 @@ * limitations under the License. */ -use ton_types::{Result, Cell, SliceData, fail, UInt256, HashmapE, HashmapType}; +use ton_types::{Result, Cell, SliceData, fail, UInt256}; use std::cmp::Ordering; use std::collections::HashMap; use std::ops::Not; @@ -77,10 +77,9 @@ macro_rules! create_handler_2r { if opc != $opc { fail!("invalid opcode"); } - let cell = slice.reference(0)?; + let cell = slice.checked_drain_reference().ok(); let code = self.load_cell(&cell)?; - slice.shrink_references(1..); - Ok(Instruction::new($mnemonic).with_param(InstructionParameter::Code { code, cell: Some(cell) })) + Ok(Instruction::new($mnemonic).with_refs(1).with_param(InstructionParameter::Code { code, cell })) } }; } @@ -92,14 +91,14 @@ macro_rules! create_handler_3r { if opc != $opc { fail!("invalid opcode"); } - let cell1 = slice.reference(0)?; - let cell2 = slice.reference(1)?; + let cell1 = slice.checked_drain_reference().ok(); + let cell2 = slice.checked_drain_reference().ok(); let code1 = self.load_cell(&cell1)?; let code2 = self.load_cell(&cell2)?; - slice.shrink_references(2..); Ok(Instruction::new($mnemonic) - .with_param(InstructionParameter::Code { code: code1, cell: Some(cell1) }) - .with_param(InstructionParameter::Code { code: code2, cell: Some(cell2) })) + .with_refs(2) + .with_param(InstructionParameter::Code { code: code1, cell: cell1 }) + .with_param(InstructionParameter::Code { code: code2, cell: cell2 })) } }; } @@ -120,6 +119,24 @@ macro_rules! check_eq { }; } +fn comment_missing_bits_and_refs(insn: &mut Instruction, missing_bits: usize, missing_refs: usize) { + if missing_bits > 0 || missing_refs > 0 { + let mut comment = String::from("missing"); + if missing_bits > 0 { + let plural = if missing_bits > 1 { "s" } else { "" }; + comment += &format!(" {} bit{}", missing_bits, plural ); + } + if missing_bits > 0 && missing_refs > 0 { + comment += " and"; + } + if missing_refs > 0 { + let plural = if missing_refs > 1 { "s" } else { "" }; + comment += &format!(" {} ref{}", missing_refs, plural); + } + insn.set_comment(comment) + } +} + pub struct Loader { handlers: Handlers, collapse: bool, @@ -146,7 +163,7 @@ impl Loader { for i in 0..orig_slice.remaining_references() { insns.push(Instruction::new(".cell").with_param( InstructionParameter::Cell { - cell: orig_slice.reference(i).unwrap(), + cell: orig_slice.reference(i).ok(), collapsed: false } )) @@ -157,13 +174,13 @@ impl Loader { match slice.remaining_references().cmp(&1) { Ordering::Less => (), Ordering::Equal => { - let next_cell = slice.reference(0).unwrap(); + let next_cell = slice.checked_drain_reference().ok(); let mut next_code = self.load_cell(&next_cell)?; if inline { code.append(&mut next_code) } else { let next = Instruction::new("IMPLICIT-JMP") - .with_param(InstructionParameter::Code { code: next_code, cell: Some(next_cell) }); + .with_param(InstructionParameter::Code { code: next_code, cell: next_cell }); code.push(next) } } @@ -174,23 +191,39 @@ impl Loader { fn load_slice(&mut self, slice: &mut SliceData) -> Result { let mut code = Code::new(); while slice.remaining_bits() > 0 { + let mut bytecode = slice.clone(); let handler = self.handlers.get_handler(&mut slice.clone())?; - let insn = handler(self, slice)?; + let mut insn = handler(self, slice)?; + + assert_eq!(bytecode.cell(), slice.cell()); + let bits = bytecode.remaining_bits() - slice.remaining_bits(); + let refs = bytecode.remaining_references() - slice.remaining_references(); + bytecode.shrink_data(..bits); + bytecode.shrink_references(..refs); + insn.set_bytecode(bytecode); + code.push(insn); } Ok(code) } - fn load_cell(&mut self, cell: &Cell) -> Result { + fn load_cell(&mut self, cell: &Option) -> Result { + if let Some(cell) = cell { + self.load_cell_impl(cell) + } else { + Ok(vec!(Instruction::new(";; missing cell"))) + } + } + fn load_cell_impl(&mut self, cell: &Cell) -> Result { if let Some(code) = self.history.get(&cell.repr_hash()) { if self.collapse { - Ok(vec!(Instruction::new(";;").with_param(InstructionParameter::Cell { cell: cell.clone(), collapsed: true }))) + Ok(vec!(Instruction::new(";;").with_param(InstructionParameter::Cell { cell: Some(cell.clone()), collapsed: true }))) } else { Ok(code.clone()) } } else { let code = self.load(&mut SliceData::load_cell_ref(cell)?, false).unwrap_or_else(|_| { // failed to load the cell - emit it as-is - vec!(Instruction::new(".cell").with_param(InstructionParameter::Cell { cell: cell.clone(), collapsed: false })) + vec!(Instruction::new(".cell").with_param(InstructionParameter::Cell { cell: Some(cell.clone()), collapsed: false })) }); self.history.insert(cell.repr_hash(), code.clone()); Ok(code) @@ -505,9 +538,9 @@ impl Loader { } else if opc < 0x80 { x = opc as i16 - 0x80; } else if opc == 0x80 { - x = (slice.get_next_int(8).unwrap() as i8) as i16; + x = (slice.get_next_int(8)? as i8) as i16; } else if opc == 0x81 { - x = slice.get_next_int(16).unwrap() as i16; + x = slice.get_next_int(16)? as i16; } Ok(Instruction::new("PUSHINT").with_param(InstructionParameter::Integer(x as isize))) } @@ -589,29 +622,26 @@ impl Loader { pub(super) fn pushref(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(8)?; check_eq!(opc, 0x88); - let cell = slice.reference(0)?; - slice.shrink_references(1..); - Ok(Instruction::new("PUSHREF").with_param(InstructionParameter::Cell { cell, collapsed: false })) + let cell = slice.checked_drain_reference().ok(); + Ok(Instruction::new("PUSHREF").with_refs(1).with_param(InstructionParameter::Cell { cell, collapsed: false })) } pub(super) fn pushrefslice(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(8)?; check_eq!(opc, 0x89); - let cell = slice.reference(0)?; - slice.shrink_references(1..); - Ok(Instruction::new("PUSHREFSLICE").with_param(InstructionParameter::Cell { cell, collapsed: false })) + let cell = slice.checked_drain_reference().ok(); + Ok(Instruction::new("PUSHREFSLICE").with_refs(1).with_param(InstructionParameter::Cell { cell, collapsed: false })) } pub(super) fn pushrefcont(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(8)?; check_eq!(opc, 0x8a); - let cell = slice.reference(0)?; + let cell = slice.checked_drain_reference().ok(); let code = self.load_cell(&cell)?; - slice.shrink_references(1..); - Ok(Instruction::new("PUSHREFCONT").with_param(InstructionParameter::Code { code, cell: Some(cell) })) + Ok(Instruction::new("PUSHREFCONT").with_refs(1).with_param(InstructionParameter::Code { code, cell })) } pub(super) fn pushslice_short(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(8)?; check_eq!(opc, 0x8b); - let x = slice.get_next_int(4).unwrap() as usize; + let x = slice.get_next_int(4)? as usize; let mut bitstring = slice.get_next_slice(x * 8 + 4)?; bitstring.trim_right(); Ok(Instruction::new("PUSHSLICE").with_param(InstructionParameter::Slice(bitstring))) @@ -619,44 +649,70 @@ impl Loader { pub(super) fn pushslice_mid(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(8)?; check_eq!(opc, 0x8c); - let r = slice.get_next_int(2)?; - check_eq!(r, 0); // TODO - let xx = slice.get_next_int(5).unwrap() as usize; - let mut bitstring = slice.get_next_slice(xx * 8 + 1)?; - bitstring.trim_right(); - Ok(Instruction::new("PUSHSLICE").with_param(InstructionParameter::Slice(bitstring))) + let r = slice.get_next_int(2)? as usize; + let xx = slice.get_next_int(5)? as usize; + let bits = xx * 8 + 1; + + let mut subslice = slice.clone(); + subslice.shrink_data(..bits); + subslice.shrink_references(..r); + subslice.trim_right(); + let missing_bits = bits - subslice.remaining_bits(); + let missing_refs = r - subslice.remaining_references(); + + slice.shrink_data(bits..); + slice.shrink_references(r..); + + let mut insn = Instruction::new("PUSHSLICE").with_refs(r).with_param(InstructionParameter::Slice(subslice)); + comment_missing_bits_and_refs(&mut insn, missing_bits, missing_refs); + Ok(insn) } pub(super) fn pushslice_long(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(8)?; check_eq!(opc, 0x8d); - let r = slice.get_next_int(3)?; - check_eq!(r, 0); // TODO - let xx = slice.get_next_int(7).unwrap() as usize; - let mut bitstring = slice.get_next_slice(xx * 8 + 6)?; - bitstring.trim_right(); - Ok(Instruction::new("PUSHSLICE").with_param(InstructionParameter::Slice(bitstring))) + let r = slice.get_next_int(3)? as usize; + let xx = slice.get_next_int(7)? as usize; + let bits = xx * 8 + 6; + + let mut subslice = slice.clone(); + subslice.shrink_data(..bits); + subslice.shrink_references(..r); + subslice.trim_right(); + let missing_bits = bits - subslice.remaining_bits(); + let missing_refs = r - subslice.remaining_references(); + + slice.shrink_data(bits..); + slice.shrink_references(r..); + + let mut insn = Instruction::new("PUSHSLICE").with_refs(r).with_param(InstructionParameter::Slice(subslice)); + comment_missing_bits_and_refs(&mut insn, missing_bits, missing_refs); + Ok(insn) } pub(super) fn pushcont_long(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(7)?; check_eq!(opc << 1, 0x8e); - let r = slice.get_next_int(2).unwrap() as usize; - let xx = slice.get_next_int(7).unwrap() as usize; + let r = slice.get_next_int(2)? as usize; + let xx = slice.get_next_int(7)? as usize; let bits = xx * 8; let mut subslice = slice.clone(); subslice.shrink_data(..bits); subslice.shrink_references(..r); + let missing_bits = bits - subslice.remaining_bits(); + let missing_refs = r - subslice.remaining_references(); let code = self.load(&mut subslice, false)?; slice.shrink_data(bits..); slice.shrink_references(r..); - Ok(Instruction::new("PUSHCONT").with_param(InstructionParameter::Code { code, cell: None })) + let mut insn = Instruction::new("PUSHCONT").with_refs(r).with_param(InstructionParameter::Code { code, cell: None }); + comment_missing_bits_and_refs(&mut insn, missing_bits, missing_refs); + Ok(insn) } pub(super) fn pushcont_short(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(4)?; check_eq!(opc, 0x9); - let x = slice.get_next_int(4).unwrap() as usize; + let x = slice.get_next_int(4)? as usize; let mut body = slice.get_next_slice(x * 8)?; let code = self.load(&mut body, true)?; Ok(Instruction::new("PUSHCONT").with_param(InstructionParameter::Code { code, cell: None })) @@ -671,14 +727,14 @@ impl Loader { where T : OperationBehavior { let opc = slice.get_next_int(8)?; check_eq!(opc, 0xa6); - let cc = slice.get_next_int(8).unwrap() as i8; + let cc = slice.get_next_int(8)? as i8; Ok(T::insn(Instruction::new("ADDCONST")).with_param(InstructionParameter::Integer(cc as isize))) } pub(super) fn mulconst(&mut self, slice: &mut SliceData) -> Result where T : OperationBehavior { let opc = slice.get_next_int(8)?; check_eq!(opc, 0xa7); - let cc = slice.get_next_int(8).unwrap() as i8; + let cc = slice.get_next_int(8)? as i8; Ok(T::insn(Instruction::new("MULCONST")).with_param(InstructionParameter::Integer(cc as isize))) } create_handler_1t!(mul, 0xa8, "MUL"); @@ -799,28 +855,28 @@ impl Loader { where T : OperationBehavior { let opc = slice.get_next_int(8)?; check_eq!(opc, 0xc0); - let yy = (slice.get_next_int(8).unwrap() as i8) as isize; + let yy = (slice.get_next_int(8)? as i8) as isize; Ok(T::insn(Instruction::new("EQINT")).with_param(InstructionParameter::Integer(yy))) } pub(super) fn lessint(&mut self, slice: &mut SliceData) -> Result where T : OperationBehavior { let opc = slice.get_next_int(8)?; check_eq!(opc, 0xc1); - let yy = (slice.get_next_int(8).unwrap() as i8) as isize; + let yy = (slice.get_next_int(8)? as i8) as isize; Ok(T::insn(Instruction::new("LESSINT")).with_param(InstructionParameter::Integer(yy))) } pub(super) fn gtint(&mut self, slice: &mut SliceData) -> Result where T : OperationBehavior { let opc = slice.get_next_int(8)?; check_eq!(opc, 0xc2); - let yy = (slice.get_next_int(8).unwrap() as i8) as isize; + let yy = (slice.get_next_int(8)? as i8) as isize; Ok(T::insn(Instruction::new("GTINT")).with_param(InstructionParameter::Integer(yy))) } pub(super) fn neqint(&mut self, slice: &mut SliceData) -> Result where T : OperationBehavior { let opc = slice.get_next_int(8)?; check_eq!(opc, 0xc3); - let yy = (slice.get_next_int(8).unwrap() as i8) as isize; + let yy = (slice.get_next_int(8)? as i8) as isize; Ok(T::insn(Instruction::new("NEQINT")).with_param(InstructionParameter::Integer(yy))) } create_handler_1!(isnan, 0xc4, "ISNAN"); @@ -1066,7 +1122,7 @@ impl Loader { pub(super) fn sdbegins(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(14)?; check_eq!(opc << 2, 0xd728); - let x = slice.get_next_int(7).unwrap() as usize; + let x = slice.get_next_int(7)? as usize; let mut bitstring = slice.get_next_slice(8 * x + 3)?; bitstring.trim_right(); Ok(Instruction::new("SDBEGINS").with_param(InstructionParameter::Slice(bitstring))) @@ -1074,7 +1130,7 @@ impl Loader { pub(super) fn sdbeginsq(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(14)?; check_eq!(opc << 2, 0xd72c); - let x = slice.get_next_int(7).unwrap() as usize; + let x = slice.get_next_int(7)? as usize; let mut bitstring = slice.get_next_slice(8 * x + 3)?; bitstring.trim_right(); Ok(Instruction::new("SDBEGINS").set_quiet().with_param(InstructionParameter::Slice(bitstring))) @@ -1220,19 +1276,17 @@ impl Loader { let opc = slice.get_next_int(15)?; check_eq!(opc << 1, 0xe3c); let n = slice.get_next_int(5)? as isize; - let cell = slice.reference(0)?; + let cell = slice.checked_drain_reference().ok(); let code = self.load_cell(&cell)?; - slice.shrink_references(1..); - Ok(Instruction::new("IFBITJMPREF").with_param(InstructionParameter::Integer(n)).with_param(InstructionParameter::Code { code, cell: Some(cell) })) + Ok(Instruction::new("IFBITJMPREF").with_refs(1).with_param(InstructionParameter::Integer(n)).with_param(InstructionParameter::Code { code, cell })) } pub(super) fn ifnbitjmpref(&mut self, slice: &mut SliceData) -> Result { let opc = slice.get_next_int(15)?; check_eq!(opc << 1, 0xe3e); let n = slice.get_next_int(5)? as isize; - let cell = slice.reference(0)?; + let cell = slice.checked_drain_reference().ok(); let code = self.load_cell(&cell)?; - slice.shrink_references(1..); - Ok(Instruction::new("IFNBITJMPREF").with_param(InstructionParameter::Integer(n)).with_param(InstructionParameter::Code { code, cell: Some(cell) })) + Ok(Instruction::new("IFNBITJMPREF").with_refs(1).with_param(InstructionParameter::Integer(n)).with_param(InstructionParameter::Code { code, cell })) } create_handler_1!(repeat, 0xe4, "REPEAT"); create_handler_1!(repeatend, 0xe5, "REPEATEND"); @@ -1597,9 +1651,8 @@ impl Loader { let opc = slice.get_next_int(14)?; check_eq!(opc << 2, 0xf4a4); let n = slice.get_next_int(10)? as usize; - let cell = slice.reference(0)?; - slice.shrink_references(1..); - Ok(Instruction::new("DICTPUSHCONST").with_param(InstructionParameter::Length(n)).with_param(InstructionParameter::Cell { cell, collapsed: false })) + let cell = slice.checked_drain_reference().ok(); + Ok(Instruction::new("DICTPUSHCONST").with_refs(1).with_param(InstructionParameter::Length(n)).with_param(InstructionParameter::Cell { cell, collapsed: false })) } create_handler_2!(pfxdictgetq, 0xf4a8, "PFXDICTGETQ"); create_handler_2!(pfxdictget, 0xf4a9, "PFXDICTGET"); @@ -1609,9 +1662,8 @@ impl Loader { let opc = slice.get_next_int(14)?; check_eq!(opc << 2, 0xf4ac); let n = slice.get_next_int(10)? as usize; - let cell = slice.reference(0)?; - slice.shrink_references(1..); - Ok(Instruction::new("PFXDICTSWITCH").with_param(InstructionParameter::Length(n)).with_param(InstructionParameter::Cell { cell, collapsed: false })) + let cell = slice.checked_drain_reference().ok(); + Ok(Instruction::new("PFXDICTSWITCH").with_refs(1).with_param(InstructionParameter::Length(n)).with_param(InstructionParameter::Cell { cell, collapsed: false })) } create_handler_2!(subdictget, 0xf4b1, "SUBDICTGET"); create_handler_2!(subdictiget, 0xf4b2, "SUBDICTIGET"); @@ -1729,319 +1781,3 @@ impl Loader { } } } - -fn match_dictpushconst_dictugetjmp(pair: &mut [Instruction]) -> Option<&mut Vec> { - let insn2 = pair.get(1)?.name(); - if insn2 != "DICTUGETJMP" { - return None - } - let insn1 = pair.get_mut(0)?; - if insn1.name() != "DICTPUSHCONST" && insn1.name() != "PFXDICTSWITCH" { - return None - } - Some(insn1.params_mut()) -} - -fn process_dictpushconst_dictugetjmp(code: &mut Code) { - for pair in code.chunks_mut(2) { - if let Some(params) = match_dictpushconst_dictugetjmp(pair) { - // TODO transform cell to code right here (for nested dicts) - params.push(InstructionParameter::CodeDictMarker) - } - } -} - -fn traverse_code_tree(code: &mut Code, process: fn(&mut Code)) { - let mut stack = vec!(code); - while let Some(code) = stack.pop() { - process(code); - for insn in code { - for param in insn.params_mut() { - match param { - InstructionParameter::Code { code: ref mut inner, cell: _ } => stack.push(inner), - _ => () - } - } - } - } -} - -pub fn elaborate_dictpushconst_dictugetjmp(code: &mut Code) { - traverse_code_tree(code, process_dictpushconst_dictugetjmp) -} - -struct DelimitedHashmapE { - dict: HashmapE, - map: HashMap, (u64, usize, Code)>, -} - -impl DelimitedHashmapE { - pub fn new(cell: Cell, key_size: usize) -> Self { - Self { - dict: HashmapE::with_hashmap(key_size, Some(cell)), - map: HashMap::new(), - } - } - fn slice_eq_data(lhs: &SliceData, rhs: &SliceData) -> bool { - let bit_len = lhs.remaining_bits(); - if bit_len != rhs.remaining_bits() { - return false; - } - let mut offset = 0; - while (offset + 8) <= bit_len { - if lhs.get_byte(offset).unwrap() != rhs.get_byte(offset).unwrap() { - return false; - } - offset += 8 - } - if (bit_len > offset) && (lhs.get_bits(offset, bit_len - offset).unwrap() != rhs.get_bits(offset, bit_len - offset).unwrap()) { - return false; - } - true - } - fn slice_eq_children(lhs: &SliceData, rhs: &SliceData) -> bool { - let refs_count = lhs.remaining_references(); - if refs_count != rhs.remaining_references() { - return false; - } - for i in 0..refs_count { - let ref1 = lhs.reference(i).unwrap(); - let ref2 = rhs.reference(i).unwrap(); - if ref1.repr_hash() != ref2.repr_hash() { - return false; - } - } - true - } - fn locate(mut slice: SliceData, target: &SliceData, path: Vec) -> Result<(Vec, usize)> { - if Self::slice_eq_children(&slice, target) { - loop { - if Self::slice_eq_data(&slice, target) { - return Ok((path, slice.pos())) - } - if slice.get_next_bit().is_err() { - break - } - } - } - for i in 0..slice.remaining_references() { - let child = SliceData::load_cell(slice.reference(i)?)?; - let mut next = path.clone(); - next.push(i as u8); - if let Ok(v) = Self::locate(child, target, next) { - return Ok(v) - } - } - fail!("not found") - } - pub fn mark(&mut self) -> Result<()> { - let dict_slice = SliceData::load_cell_ref(self.dict.data().unwrap())?; - for entry in self.dict.iter() { - let (key, mut slice) = entry?; - let id = SliceData::load_builder(key)?.get_next_int(self.dict.bit_len())?; - let loc = Self::locate(dict_slice.clone(), &slice, vec!())?; - let mut loader = Loader::new(false); - let code = loader.load(&mut slice, true)?; - if self.map.insert(loc.0, (id, loc.1, code)).is_some() { - fail!("non-unique path found") - } - } - Ok(()) - } - fn print_impl(&self, cell: &Cell, indent: &str, path: Vec) -> String { - let mut text = String::new(); - text += &format!("{}.cell ", indent); - text += &format!("{{ ;; #{}\n", cell.repr_hash().to_hex_string()); - let inner_indent = String::from(" ") + indent; - let mut slice = SliceData::load_cell_ref(cell).unwrap(); - if let Some((id, offset, code)) = self.map.get(&path) { - let aux = slice.get_next_slice(*offset).unwrap(); - text += &format!("{}.blob x{}\n", inner_indent, aux.to_hex_string()); - text += &format!("{};; method {}\n", inner_indent, id); - text += &print_code(code, &inner_indent); - } else { - if slice.remaining_bits() > 0 { - text += &format!("{}.blob x{}\n", inner_indent, slice.to_hex_string()); - } - for i in 0..cell.references_count() { - let mut path = path.clone(); - path.push(i as u8); - text += &self.print_impl(&cell.reference(i).unwrap(), inner_indent.as_str(), path); - } - } - text += &format!("{}}}\n", indent); - text - } - pub fn print(&self, indent: &str) -> String { - self.print_impl(self.dict.data().unwrap(), indent, vec!()) - } -} - -fn print_code_dict(cell: &Cell, key_size: usize, indent: &str) -> Result { - let mut map = DelimitedHashmapE::new(cell.clone(), key_size); - map.mark()?; - Ok(map.print(indent)) -} - -fn print_cell(cell: &Cell, indent: &str, dot_cell: bool) -> String { - let mut text = String::new(); - if dot_cell { - text += &format!("{}.cell ", indent); - } - text += &format!("{{ ;; #{}\n", cell.repr_hash().to_hex_string()); - let inner_indent = String::from(" ") + indent; - if cell.bit_length() > 0 { - text += &format!("{}.blob x{}\n", inner_indent, cell.to_hex_string(true)); - } - let refs = cell.references_count(); - for i in 0..refs { - text += &print_cell(&cell.reference(i).unwrap(), inner_indent.as_str(), true); - } - text += &format!("{}}}", indent); - if dot_cell { - text += "\n"; - } - text -} - -fn print_dictpushconst(insn: &Instruction, indent: &str) -> String { - let key_length = if let Some(InstructionParameter::Length(l)) = insn.params().get(0) { - *l - } else { - unreachable!() - }; - let cell = if let Some(InstructionParameter::Cell { cell, collapsed }) = insn.params().get(1) { - assert!(collapsed == &false); - cell - } else { - unreachable!() - }; - let text = if let Some(InstructionParameter::CodeDictMarker) = insn.params().get(2) { - print_code_dict(cell, key_length, indent) - .unwrap_or_else(|_| print_cell(cell, indent, true)) - } else { - print_cell(cell, indent, true) - }; - format!("{} {}\n{}", insn.name(), key_length, text) -} - -pub fn print_code(code: &Code, indent: &str) -> String { - print_code_ex(code, indent, true) -} - -pub fn print_code_ex(code: &Code, indent: &str, full: bool) -> String { - let mut disasm = String::new(); - for insn in code { - disasm += indent; - if full { - match insn.name() { - "DICTPUSHCONST" | "PFXDICTSWITCH" => { - // TODO better improve assembler for these two insns - disasm += &print_dictpushconst(insn, indent); - continue - } - "IMPLICIT-JMP" => { - if let Some(InstructionParameter::Code { code, cell }) = insn.params().get(0) { - let hash = cell.as_ref().unwrap().repr_hash().to_hex_string(); - disasm += &format!(".cell {{ ;; #{}\n", hash); - let inner_indent = String::from(" ") + indent; - disasm += &print_code(code, inner_indent.as_str()); - disasm += indent; - disasm += "}\n"; - } else { - unreachable!() - } - continue - } - _ => () - } - } - disasm += insn.name(); - if insn.is_quiet() { - disasm += "Q"; - } - let len = insn.params().len(); - if len > 0 { - disasm += " "; - } - for (index, param) in insn.params().iter().enumerate() { - let last = len == (index + 1); - let mut curr_is_block = false; - match param { - InstructionParameter::BigInteger(i) => { - disasm += format!("{}", i).as_str(); - } - InstructionParameter::ControlRegister(c) => { - disasm += format!("c{}", c).as_str(); - } - //InstructionParameter::DivisionMode(_) => { - // todo!() - //} - InstructionParameter::Integer(i) => { - disasm += format!("{}", i).as_str(); - } - InstructionParameter::Length(l) => { - disasm += format!("{}", l).as_str(); - } - InstructionParameter::LengthAndIndex(l, i) => { - disasm += format!("{}, {}", l, i).as_str(); - } - InstructionParameter::Nargs(n) => { - disasm += format!("{}", n).as_str(); - } - InstructionParameter::Pargs(p) => { - disasm += format!("{}", p).as_str(); - } - InstructionParameter::Rargs(r) => { - disasm += format!("{}", r).as_str(); - } - InstructionParameter::Slice(s) => { - disasm += format!("x{}", s.to_hex_string()).as_str(); - } - InstructionParameter::StackRegister(r) => { - disasm += format!("s{}", r).as_str(); - } - InstructionParameter::StackRegisterPair(ra, rb) => { - disasm += format!("s{}, s{}", ra, rb).as_str(); - } - InstructionParameter::StackRegisterTriple(ra, rb, rc) => { - disasm += format!("s{}, s{}, s{}", ra, rb, rc).as_str(); - } - InstructionParameter::Code { code, cell } => { - if full { - if let Some(cell) = cell { - disasm += &format!("{{ ;; #{}\n", cell.repr_hash().to_hex_string()); - } else { - disasm += "{\n"; - } - let inner_indent = String::from(" ") + indent; - disasm += &print_code(code, inner_indent.as_str()); - disasm += indent; - disasm += "}"; - curr_is_block = true; - } - } - InstructionParameter::Cell { cell, collapsed } => { - if full { - if *collapsed { - assert!(insn.name() == ";;"); - disasm += ""; - } else { - disasm += &print_cell(cell, indent, false); - } - curr_is_block = true; - } - } - InstructionParameter::CodeDictMarker => { - // handled above for DICTPUSHCONST - unreachable!() - } - } - if !last && !curr_is_block { - disasm += ", "; - } - } - disasm += "\n"; - } - disasm -} diff --git a/src/disasm/mod.rs b/src/disasm/mod.rs index 14307e7d..fcdb5767 100644 --- a/src/disasm/mod.rs +++ b/src/disasm/mod.rs @@ -11,9 +11,11 @@ * limitations under the License. */ +pub mod codedict; pub mod commands; mod handlers; pub mod loader; +pub mod fmt; #[cfg(test)] mod tests; pub mod types; diff --git a/src/disasm/tests.rs b/src/disasm/tests.rs index dd1edeac..0f193912 100644 --- a/src/disasm/tests.rs +++ b/src/disasm/tests.rs @@ -93,3 +93,25 @@ fn round_trip_tonix() { round_trip_test(&filename, true); }) } + +fn check(code: &str, text: &str) { + let mut slice = SliceData::from_string(code).unwrap(); + let text_disasm = disasm(&mut slice); + assert_eq!(text, &text_disasm); +} + +#[test] +fn disasm_fragment() { + check("70", "PUSHINT 0\n"); + check("88", "PUSHREF {\n ;; missing cell\n}\n"); + check("8b04", "PUSHSLICE x4_\n"); + check("8c0800000000", "PUSHSLICE x000000004_\n"); + check("8c40", "PUSHSLICE x4_ ;; missing 1 ref\n"); + check("8c80", "PUSHSLICE x4_ ;; missing 2 refs\n"); + check("8e80", "PUSHCONT {\n} ;; missing 1 ref\n"); + check("8e81", "PUSHCONT {\n} ;; missing 8 bits and 1 ref\n"); + check("920000", "PUSHCONT {\n NOP\n NOP\n}\n"); + check("e300", "IFREF {\n ;; missing cell\n}\n"); + check("e30f", "IFREFELSEREF {\n ;; missing cell\n}{\n ;; missing cell\n}\n"); + check("f4a420", "DICTPUSHCONST 32 ;; missing dict ref\n"); +} diff --git a/src/disasm/types.rs b/src/disasm/types.rs index fbc6e372..d281eb21 100644 --- a/src/disasm/types.rs +++ b/src/disasm/types.rs @@ -21,11 +21,19 @@ pub struct Instruction { name: &'static str, params: Vec, quiet: bool, + comment: Option, + bytecode: Option, + refs: usize, } impl Instruction { pub fn new(name: &'static str) -> Self { - Self { name, params: vec!(), quiet: false } + Self { name, params: vec!(), quiet: false, comment: None, bytecode: None, refs: 0 } + } + pub fn with_refs(self, refs: usize) -> Self { + let mut clone = self; + clone.refs = refs; + clone } pub fn with_param(self, param: InstructionParameter) -> Self { let mut clone = self; @@ -49,6 +57,21 @@ impl Instruction { pub fn is_quiet(&self) -> bool { self.quiet } + pub fn comment(&self) -> Option<&String> { + self.comment.as_ref() + } + pub fn set_comment(&mut self, comment: String) { + self.comment = Some(comment) + } + pub fn bytecode(&self) -> Option<&SliceData> { + self.bytecode.as_ref() + } + pub fn set_bytecode(&mut self, bytecode: SliceData) { + self.bytecode = Some(bytecode); + } + pub fn refs(&self) -> usize { + self.refs + } } #[derive(Debug, Clone)] @@ -67,7 +90,7 @@ pub enum InstructionParameter { StackRegisterPair(isize, isize), StackRegisterTriple(isize, isize, isize), Code { code: Code, cell: Option }, - Cell { cell: Cell, collapsed: bool }, + Cell { cell: Option, collapsed: bool }, CodeDictMarker, } diff --git a/src/main.rs b/src/main.rs index c7688d2d..7f9b03ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -189,6 +189,11 @@ fn linker_main() -> Status { (@arg TVC: +required +takes_value "Path to tvc file") (@arg RAW: --raw "Interpret the input as a raw TOC of code") ) + (@subcommand fragment => + (about: "disassembles bytestring fragment") + (version: build_info.as_str()) + (@arg FRAGMENT: +required +takes_value "Bytestring") + ) ) (@setting SubcommandRequired) ).get_matches(); From be271bf0a25df8d164c84fec23c4622f6059eaae Mon Sep 17 00:00:00 2001 From: tonjen Date: Fri, 17 Mar 2023 14:57:54 +0000 Subject: [PATCH 2/6] Preparing to merge with the master --- Cargo.lock | 69 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50c5ee41..ab6115e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + [[package]] name = "arrayref" version = "0.3.6" @@ -58,13 +64,14 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "assert_cmd" -version = "2.0.8" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e" +checksum = "ec0b2340f55d9661d76793b2bfc2eb0e62689bd79d067a95707ea762afd5e9dd" dependencies = [ + "anstyle", "bstr 1.3.0", "doc-comment", - "predicates", + "predicates 3.0.1", "predicates-core", "predicates-tree", "wait-timeout", @@ -145,9 +152,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -208,9 +215,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "js-sys", @@ -431,7 +438,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", ] @@ -645,9 +652,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "link-cplusplus" @@ -855,17 +862,29 @@ dependencies = [ "regex", ] +[[package]] +name = "predicates" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba7d6ead3e3966038f68caa9fc1f860185d95a793180bbcfe0d0da47b3961ed" +dependencies = [ + "anstyle", + "difflib", + "itertools", + "predicates-core", +] + [[package]] name = "predicates-core" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" dependencies = [ "predicates-core", "termtree", @@ -873,18 +892,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -1060,18 +1079,18 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" dependencies = [ "proc-macro2", "quote", @@ -1202,9 +1221,9 @@ dependencies = [ [[package]] name = "termtree" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "textwrap" @@ -1339,7 +1358,7 @@ dependencies = [ "log", "num", "num-traits", - "predicates", + "predicates 2.1.5", "rand 0.8.5", "rayon", "regex", From d59775b1b6bd0353d177596caac952ea7aae1221 Mon Sep 17 00:00:00 2001 From: Mikhael Skvortsov Date: Mon, 20 Mar 2023 13:54:37 +0300 Subject: [PATCH 3/6] disasm: refactoring --- src/disasm/codedict.rs | 42 ++++++++++++------------ src/disasm/commands.rs | 13 +++----- src/disasm/fmt.rs | 72 ++++++++++++++++++++++-------------------- src/disasm/loader.rs | 8 ++--- src/disasm/types.rs | 35 ++++++++++++++++++-- 5 files changed, 100 insertions(+), 70 deletions(-) diff --git a/src/disasm/codedict.rs b/src/disasm/codedict.rs index 12e50d0c..7ecf3d13 100644 --- a/src/disasm/codedict.rs +++ b/src/disasm/codedict.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use ton_types::{Cell, HashmapE, HashmapType, Result, SliceData, fail}; use super::{ types::{Instruction, InstructionParameter, Code}, - loader::Loader, fmt::print_code + loader::Loader }; fn match_dictpushconst_dictugetjmp(pair: &mut [Instruction]) -> Option<&mut Vec> { @@ -30,32 +30,34 @@ fn match_dictpushconst_dictugetjmp(pair: &mut [Instruction]) -> Option<&mut Vec< Some(insn1.params_mut()) } -fn process_dictpushconst_dictugetjmp(code: &mut Code) { - for pair in code.chunks_mut(2) { - if let Some(params) = match_dictpushconst_dictugetjmp(pair) { - // TODO transform cell to code right here (for nested dicts) - params.push(InstructionParameter::CodeDictMarker) +impl Code { + fn process_dictpushconst_dictugetjmp(code: &mut Code) { + for pair in code.chunks_mut(2) { + if let Some(params) = match_dictpushconst_dictugetjmp(pair) { + // TODO transform cell to code right here (for nested dicts) + params.push(InstructionParameter::CodeDictMarker) + } } } -} -fn traverse_code_tree(code: &mut Code, process: fn(&mut Code)) { - let mut stack = vec!(code); - while let Some(code) = stack.pop() { - process(code); - for insn in code { - for param in insn.params_mut() { - match param { - InstructionParameter::Code { code: ref mut inner, cell: _ } => stack.push(inner), - _ => () + fn traverse_code_tree(&mut self, process: fn(&mut Code)) { + let mut stack = vec!(self); + while let Some(code) = stack.pop() { + process(code); + for insn in code.iter_mut() { + for param in insn.params_mut() { + match param { + InstructionParameter::Code { code: ref mut inner, cell: _ } => stack.push(inner), + _ => () + } } } } } -} -pub fn elaborate_dictpushconst_dictugetjmp(code: &mut Code) { - traverse_code_tree(code, process_dictpushconst_dictugetjmp) + pub fn elaborate_dictpushconst_dictugetjmp(&mut self) { + self.traverse_code_tree(Self::process_dictpushconst_dictugetjmp) + } } pub(super) struct DelimitedHashmapE { @@ -146,7 +148,7 @@ impl DelimitedHashmapE { let aux = slice.get_next_slice(*offset).unwrap(); text += &format!("{}.blob x{}\n", inner_indent, aux.to_hex_string()); text += &format!("{};; method {}\n", inner_indent, id); - text += &print_code(code, &inner_indent, true, 0); + text += &code.print(&inner_indent, true, 0); } else { if slice.remaining_bits() > 0 { text += &format!("{}.blob x{}\n", inner_indent, slice.to_hex_string()); diff --git a/src/disasm/commands.rs b/src/disasm/commands.rs index 1b82c09a..937b4672 100644 --- a/src/disasm/commands.rs +++ b/src/disasm/commands.rs @@ -20,12 +20,7 @@ use ton_types::cells_serialization::deserialize_cells_tree; use ton_types::{Cell, HashmapE, HashmapType, SliceData, UInt256, Status}; use std::io::Cursor; -use super::{ - codedict::elaborate_dictpushconst_dictugetjmp, - fmt::print_code, - loader::Loader, - types::Shape, -}; +use super::{loader::Loader, types::Shape}; pub fn disasm_command(m: &ArgMatches) -> Status { if let Some(m) = m.subcommand_matches("dump") { @@ -317,7 +312,7 @@ fn disasm_fragment_command(m: &ArgMatches) -> Status { let mut loader = Loader::new(false); let code = loader.load(&mut slice, false).unwrap(); - let text = print_code(&code, "", true, 12); + let text = code.print("", true, 12); print!("{}", text); Ok(()) @@ -330,6 +325,6 @@ pub(super) fn disasm(slice: &mut SliceData) -> String { pub(super) fn disasm_ex(slice: &mut SliceData, collapsed: bool) -> String { let mut loader = Loader::new(collapsed); let mut code = loader.load(slice, false).unwrap(); - elaborate_dictpushconst_dictugetjmp(&mut code); - print_code(&code, "", true, 0) + code.elaborate_dictpushconst_dictugetjmp(); + code.print("", true, 0) } diff --git a/src/disasm/fmt.rs b/src/disasm/fmt.rs index f8e19d15..1e88a446 100644 --- a/src/disasm/fmt.rs +++ b/src/disasm/fmt.rs @@ -92,45 +92,47 @@ fn print_bytecode(slice: Option<(&SliceData, usize)>, bytecode_width: usize) -> text } -pub fn print_code(code: &Code, indent: &str, full: bool, bytecode_width: usize) -> String { - let mut text = String::new(); - for insn in code { - text += &print_bytecode(insn.bytecode().map(|v| (v, insn.refs())), bytecode_width); - text += indent; - if full { - match insn.name() { - "DICTPUSHCONST" | "PFXDICTSWITCH" => { - // TODO better improve assembler for these two insns - text += &print_dictpushconst(insn, indent); - continue - } - "IMPLICIT-JMP" => { - if let Some(InstructionParameter::Code { code, cell }) = insn.params().get(0) { - let hash = cell.as_ref().unwrap().repr_hash().to_hex_string(); - text += &format!(".cell {{ ;; #{}\n", hash); - let inner_indent = String::from(" ") + indent; - text += &print_code(code, &inner_indent, full, bytecode_width); - text += indent; - text += "}\n"; - } else { - unreachable!() +impl Code { + pub fn print(&self, indent: &str, full: bool, bytecode_width: usize) -> String { + let mut text = String::new(); + for insn in self.iter() { + text += &print_bytecode(insn.bytecode().map(|v| (v, insn.refs())), bytecode_width); + text += indent; + if full { + match insn.name() { + "DICTPUSHCONST" | "PFXDICTSWITCH" => { + // TODO better improve assembler for these two insns + text += &print_dictpushconst(insn, indent); + continue + } + "IMPLICIT-JMP" => { + if let Some(InstructionParameter::Code { code, cell }) = insn.params().get(0) { + let hash = cell.as_ref().unwrap().repr_hash().to_hex_string(); + text += &format!(".cell {{ ;; #{}\n", hash); + let inner_indent = String::from(" ") + indent; + text += &code.print(&inner_indent, full, bytecode_width); + text += indent; + text += "}\n"; + } else { + unreachable!() + } + continue } - continue + _ => () } - _ => () } + text += insn.name(); + if insn.is_quiet() { + text += "Q"; + } + text += &print_insn_params(insn.params(), indent, full, bytecode_width); + if let Some(comment) = insn.comment() { + text += &format!(" ;; {}", comment); + } + text += "\n"; } - text += insn.name(); - if insn.is_quiet() { - text += "Q"; - } - text += &print_insn_params(insn.params(), indent, full, bytecode_width); - if let Some(comment) = insn.comment() { - text += &format!(" ;; {}", comment); - } - text += "\n"; + text } - text } fn print_insn_params(params: &Vec, indent: &str, full: bool, bytecode_width: usize) -> String { @@ -191,7 +193,7 @@ fn print_insn_params(params: &Vec, indent: &str, full: boo text += "{\n"; } let inner_indent = String::from(" ") + indent; - text += &print_code(code, &inner_indent, full, bytecode_width); + text += &code.print(&inner_indent, full, bytecode_width); text += &print_bytecode(None, bytecode_width); text += indent; text += "}"; diff --git a/src/disasm/loader.rs b/src/disasm/loader.rs index 6158dbd6..5f1c2a0e 100644 --- a/src/disasm/loader.rs +++ b/src/disasm/loader.rs @@ -157,7 +157,7 @@ impl Loader { Ok(code) => code, Err(_) => { // failed to load the slice - emit it as-is - let mut insns = vec!( + let mut insns = Code::single( Instruction::new(".blob").with_param(InstructionParameter::Slice(orig_slice.clone())) ); for i in 0..orig_slice.remaining_references() { @@ -210,20 +210,20 @@ impl Loader { if let Some(cell) = cell { self.load_cell_impl(cell) } else { - Ok(vec!(Instruction::new(";; missing cell"))) + Ok(Code::single(Instruction::new(";; missing cell"))) } } fn load_cell_impl(&mut self, cell: &Cell) -> Result { if let Some(code) = self.history.get(&cell.repr_hash()) { if self.collapse { - Ok(vec!(Instruction::new(";;").with_param(InstructionParameter::Cell { cell: Some(cell.clone()), collapsed: true }))) + Ok(Code::single(Instruction::new(";;").with_param(InstructionParameter::Cell { cell: Some(cell.clone()), collapsed: true }))) } else { Ok(code.clone()) } } else { let code = self.load(&mut SliceData::load_cell_ref(cell)?, false).unwrap_or_else(|_| { // failed to load the cell - emit it as-is - vec!(Instruction::new(".cell").with_param(InstructionParameter::Cell { cell: Some(cell.clone()), collapsed: false })) + Code::single(Instruction::new(".cell").with_param(InstructionParameter::Cell { cell: Some(cell.clone()), collapsed: false })) }); self.history.insert(cell.repr_hash(), code.clone()); Ok(code) diff --git a/src/disasm/types.rs b/src/disasm/types.rs index d281eb21..df582a2c 100644 --- a/src/disasm/types.rs +++ b/src/disasm/types.rs @@ -11,10 +11,41 @@ * limitations under the License. */ -use std::collections::HashMap; +use std::{collections::HashMap, slice::ChunksMut}; use ton_types::{Cell, Result, /*Bitmask,*/ SliceData, fail}; -pub type Code = Vec; +#[derive(Debug, Clone)] +pub struct Code { + storage: Vec +} + +impl Code { + pub fn new() -> Self { + Self { + storage: Vec::new() + } + } + pub fn single(insn: Instruction) -> Self { + Self { + storage: vec!(insn) + } + } + pub fn append(&mut self, other: &mut Self) { + self.storage.append(&mut other.storage) + } + pub fn push(&mut self, insn: Instruction) { + self.storage.push(insn) + } + pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { + self.storage.chunks_mut(chunk_size) + } + pub fn iter(&self) -> impl Iterator{ + self.storage.iter() + } + pub fn iter_mut(&mut self) -> impl Iterator{ + self.storage.iter_mut() + } +} #[derive(Debug, Clone)] pub struct Instruction { From bd158959ac097f1675606124e6c0bda061f39c7d Mon Sep 17 00:00:00 2001 From: tonjen Date: Mon, 20 Mar 2023 11:14:03 +0000 Subject: [PATCH 4/6] Preparing to merge with the master --- Cargo.lock | 59 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab6115e9..c9a3b205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,7 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0b2340f55d9661d76793b2bfc2eb0e62689bd79d067a95707ea762afd5e9dd" dependencies = [ "anstyle", - "bstr 1.3.0", + "bstr 1.4.0", "doc-comment", "predicates 3.0.1", "predicates-core", @@ -170,9 +170,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" dependencies = [ "memchr", "once_cell", @@ -366,9 +366,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" +checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038" dependencies = [ "cc", "cxxbridge-flags", @@ -378,9 +378,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" +checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca" dependencies = [ "cc", "codespan-reporting", @@ -388,24 +388,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 2.0.2", ] [[package]] name = "cxxbridge-flags" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" +checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31" [[package]] name = "cxxbridge-macro" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" +checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.2", ] [[package]] @@ -506,7 +506,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] @@ -754,7 +754,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1079,22 +1079,22 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.156" +version = "1.0.157" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.157" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.2", ] [[package]] @@ -1187,6 +1187,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -1195,7 +1206,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "unicode-xid", ] @@ -1458,7 +1469,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -1480,7 +1491,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1539,7 +1550,7 @@ checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] From e816109370de208a466b5d97d66513bf227d413e Mon Sep 17 00:00:00 2001 From: tonjen Date: Mon, 20 Mar 2023 11:28:05 +0000 Subject: [PATCH 5/6] Preparing to merge with the master --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9a3b205..e8b33d97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,7 +388,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.2", + "syn 2.0.3", ] [[package]] @@ -405,7 +405,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.3", ] [[package]] @@ -1094,7 +1094,7 @@ checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.3", ] [[package]] @@ -1189,9 +1189,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" +checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60" dependencies = [ "proc-macro2", "quote", From c0b93deb30c8de4c4bf178ce5dc580972ef3cacd Mon Sep 17 00:00:00 2001 From: tonjen Date: Mon, 20 Mar 2023 11:42:50 +0000 Subject: [PATCH 6/6] Preparing to merge with the master --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8b33d97..8bfda4e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1079,18 +1079,18 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.157" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.157" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote",