diff --git a/app/Cargo.toml b/app/Cargo.toml index 74df678..2338b09 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -8,15 +8,15 @@ name = "polkarun" crate-type = ["cdylib", "rlib"] [dependencies] -polkavm = { git = "https://github.com/koute/polkavm" } +polkavm-common = { git = "https://github.com/koute/polkavm" } gloo-net = { version = "0.5.0", features = ["http"] } -leptos = { version = "0.5.4", features = ["csr", "nightly", "experimental-islands"] } -leptos_meta = { version = "0.5.4", features = ["csr", "nightly"] } -leptos_router = { version = "0.5.4", features = ["csr", "nightly"] } -reqwest = { version = "0.11.23" } -toml = "0.8.8" -js-sys = { version = "0.3.66" } -web-sys = { version = "0.3.66", features = ["HtmlInputElement", "DataTransfer", "DragEvent", "File", "FileList", "FileReader", "ProgressEvent"] } +leptos = { version = "0.6.11", features = ["csr", "nightly", "experimental-islands"] } +leptos_meta = { version = "0.6.11", features = ["csr", "nightly"] } +leptos_router = { version = "0.6.11", features = ["csr", "nightly"] } +reqwest = { version = "0.12.3" } +toml = "0.8.12" +js-sys = { version = "0.3.69" } +web-sys = { version = "0.3.69", features = ["HtmlInputElement", "DataTransfer", "DragEvent", "File", "FileList", "FileReader", "ProgressEvent"] } # serialization ron = "0.8.1" @@ -25,7 +25,7 @@ serde = { version = "1", features = ["derive"] } # dependecies for client (enable when csr or hydrate set) wasm-bindgen = { version = "0.2.92" } -log = "0.4.20" +log = "0.4.21" cached = { version = "0.47.0", optional = true } console_log = { version = "1"} console_error_panic_hook = { version = "0.1.7"} diff --git a/app/package.json b/app/package.json index 62a38d4..db02b20 100644 --- a/app/package.json +++ b/app/package.json @@ -7,10 +7,10 @@ "license": "MIT", "publish": false, "devDependencies": { - "@iconify-json/mdi": "1.1.64", - "@unocss/cli": "0.56.5", - "@unocss/preset-icons": "^0.58.3", - "inter-ui": "3.19.3", - "unocss": "0.56.5" + "@iconify-json/mdi": "1.1.66", + "@unocss/cli": "0.59.3", + "@unocss/preset-icons": "^0.59.3", + "inter-ui": "4.0.2", + "unocss": "0.59.3" } } diff --git a/app/src/disassembler.rs b/app/src/disassembler.rs index 77f7128..1c21151 100644 --- a/app/src/disassembler.rs +++ b/app/src/disassembler.rs @@ -1,24 +1,24 @@ use leptos::*; -use polkavm::ProgramBlob; +use polkavm_common::program::{ProgramBlob, Instruction}; use crate::file_upload::FileUploadComponent; use serde::{Deserialize, Serialize}; -use std::fmt::Write; -// use ron::de::from_str; #[derive(Clone, Debug)] struct DisassembledLine { offset: String, hex: String, assembly: String, + operation: String, } // Helper function to create a new DisassembledLine impl DisassembledLine { - fn new(offset: usize, hex: String, assembly: String) -> Self { + fn new(offset: usize, hex: String, assembly: String, operation: String) -> Self { Self { offset: format!("{:06X}", offset), hex, assembly, + operation, } } } @@ -42,52 +42,13 @@ struct MainMenu { #[component] fn MenuButton(item: MenuItem) -> impl IntoView { - // let (toggle_submenu, set_toggle_submenu) = create_signal(false); - - // let item_type = item.item_type.clone(); - // let toggle_submenu_handler = move || { - // match item_type { - // MenuItemType::SubMenu(_) => { - // set_toggle_submenu(!toggle_submenu.get()); - // } - // _ => {} - // } - // }; view! { } } @@ -95,13 +56,6 @@ fn MenuButton(item: MenuItem) -> impl IntoView { // MainMenu #[component] fn MainMenu() -> impl IntoView { - // fn load_menu() -> Result { - // let content = include_str!("pages/disassembler.ron"); - // println!("{}", content); - // from_str(content).map_err(|e| e.into()) - // } - // - // let menu = load_menu().expect("Failed to load menu"); let menu = MainMenu { items: vec![ @@ -243,30 +197,97 @@ pub fn Disassembler() -> impl IntoView { } + fn serialize_instruction(instruction: &Instruction) -> (String, usize) { + let mut buffer = [0u8; 16]; // maximum instruction size? + let size = instruction.serialize_into(&mut buffer); + + let hex_representation = buffer[..size].iter() + .map(|byte| format!("{:02x}", byte)) + .collect::>() + .join(" "); + + (hex_representation, size) + } + + fn find_first_instruction_binary(blob: &ProgramBlob) -> Result, String> { + let first_instruction = blob.instructions().next() + .ok_or("No instructions in the blob")? + .map_err(|e| format!("Error parsing first instruction: {}", e))?; + + let (binary, _) = serialize_instruction(&first_instruction); + + // Convert the binary string to a byte array + let mut result = Vec::new(); + for byte_str in binary.split_whitespace() { + let byte = u8::from_str_radix(byte_str, 16) + .map_err(|e| format!("Error parsing byte: {}", e))?; + result.push(byte); + } + + Ok(result) + } + + // Function to find the true byte offset of the first instruction in the blob + fn find_true_byte_offset(blob: &ProgramBlob, first_instruction_binary: &[u8]) -> Result { + let blob_bytes = blob.as_bytes(); + + blob_bytes.windows(first_instruction_binary.len()) + .position(|window| window == first_instruction_binary) + .ok_or_else(|| "Binary sequence not found".to_string()) + } + + // Updated calculate_program_base_address function + fn calculate_program_base_address(blob: &ProgramBlob) -> Result { + let first_instruction_binary = find_first_instruction_binary(blob)?; + println!("First instruction binary: {:?}", first_instruction_binary); + find_true_byte_offset(blob, &first_instruction_binary) + + } + fn disassemble_into_lines(data: &[u8]) -> Result, &'static str> { let blob = ProgramBlob::parse(data).map_err(|_| "Failed to parse blob")?; + // Assuming you have a function that calculates the true base address of the program + let program_base_address = calculate_program_base_address(&blob) + .map_err(|_| "Failed to calculate program base address")?; + let mut result = Vec::new(); - let mut offset = 0usize; - let mut hex_buffer = String::with_capacity(64); // Adjust size as needed + let mut current_byte_offset: usize = 0; // Start from the calculated program base address for maybe_instruction in blob.instructions() { - hex_buffer.clear(); - match maybe_instruction { Ok(instruction) => { - let mut serialized = [0u8; 32]; // Adjust hard coded size as needed + let mut serialized = [0u8; 32]; // Adjust size as needed let size = instruction.serialize_into(&mut serialized); - - for &byte in &serialized[..size] { - write!(hex_buffer, "{:02X} ", byte).expect("Writing to string failed"); - } - - result.push(DisassembledLine::new(offset, hex_buffer.clone(), instruction.to_string())); - offset += size; + let hex_buffer = serialized[..size] + .iter() + .map(|byte| format!("{:02X} ", byte)) + .collect::(); + + // Extract the opcode name from the instruction + let opcode_name = format!("{:?}", instruction.opcode()); + + // Calculate the true offset for this instruction + let true_offset = current_byte_offset + program_base_address; + + result.push(DisassembledLine::new( + true_offset, + hex_buffer, + instruction.to_string(), + opcode_name, // Pass the opcode name to the operation field + )); + current_byte_offset += size; }, Err(error) => { - result.push(DisassembledLine::new(offset, "ERROR".to_string(), format!("Error: {}", error))); + // Even in case of an error, calculate the true offset + let true_offset = current_byte_offset + program_base_address; + + result.push(DisassembledLine::new( + true_offset, + "ERROR".to_string(), + format!("Error: {}", error), + "Unknown".to_string(), // Use a placeholder like "Unknown" for errors + )); } } } @@ -316,7 +337,7 @@ pub fn Disassembler() -> impl IntoView {
-
+
impl IntoView {
{/* flex container for headers */}
-
Offset
-
Hex
-
Assembly
-
Hint
+
"Offset"
+
"Hex"
+
"Assembly"
+
"Operation"
{/* Flex container for content */} @@ -408,8 +429,7 @@ pub fn Disassembler() -> impl IntoView {
{&line.assembly}
- {/* Placeholder for Hint */} -

+                                                
{&line.operation}
} diff --git a/app/src/home.rs b/app/src/home.rs index 0e34501..692d4a0 100644 --- a/app/src/home.rs +++ b/app/src/home.rs @@ -6,70 +6,15 @@ pub fn Home() -> impl IntoView {

"polka.run"

-
-

- "PolkaVM: Stepping up the Blockchain Virtual Machines" -

+

- "PolkaVM, a new RISC-V based virtual machine by Polkadot, promises to transform the blockchain landscape. Jan from Polkadot's team at Parity introduced this innovative VM, highlighting its unique features and potential benefits." + "PolkaVM is general purpose virtual machine for user-level applications. " + "It runs on x86 architechture linux based operating systems and transpiles. " + "Rust/C/asm guest programs into RISC-V based bytecode. We have built graphical " + "interface for disassembler to improve accessibility to understand binaries PolkaVM produces. "

-

- "Background: Polkadot and WebAssembly" -

-

- "Polkadot has heavily utilized WebAssembly (WASM) since its inception, utilizing it for both its state transition function, known as the runtime, and its native smart contract solution. WASM's speed and efficiency initially made it an attractive choice. However, it presented several challenges." -

-
    -
  • - "Complexity" - " - WASM's instruction set grew from 172 to over 400 instructions, creating a complex and constantly evolving environment." -
  • -
  • - Determinism - " - Blockchain technology demands 100% determinism, but WASM does not fully meet this requirement." -
  • -
-
-
-

"PolkaVM's Advantages"

-
    -
  • - "Performance" - " - Early benchmarks show PolkaVM nearly matching native performance." -
  • -
  • - "Efficiency" - " - Exceptional compile-time performance, significantly outpacing competitors." -
  • -
  • - "Simplicity and Stability" - " - Leverages the RISC-V architecture for a simpler, stable baseline." -
  • -
  • - "Security" - " - Runs guest programs in separate processes and namespaces, similar to Docker containers." -
  • -
-

"Future Prospects"

-

- "PolkaVM, still in its research phase, has shown impressive results in a short period." -

-
    -
  • - "Time-Travel Debugging" - " - A unique feature allowing backward navigation during debugging." -
  • -
  • - "Cross-Platform Compatibility" - " - Aiming to support different CPU architectures." -
  • -
  • - "Optimization and Extensions" - " - Continuous improvements in performance and support for RISC-V extensions." -
  • -
-
+
                         "╔══════════════════════════════════════════════════════════════════════════════╗\n"
                         "║...:OdKK;  ;OK;..OcXXXd0XxdkdOXNX0oX0lNdNWNWWx0WkWo0OdWXkWdK ; kNMX0d0XMMx;XMk║\n"
@@ -109,13 +54,7 @@ pub fn Home() -> impl IntoView {
                         "╚══════════════════════════════════════════════════════════════════════════════╝\n"
                     
-
-
-

- "PolkaVM's combination of security, determinism, and performance positions it as a promising - lightweight virtual machine, making it ideal for a wide range of applications." -

-
+
} } diff --git a/app/style/output.css b/app/style/output.css index 333fe56..ffa9c91 100644 --- a/app/style/output.css +++ b/app/style/output.css @@ -21,7 +21,6 @@ .static{position:static;} .m-0{margin:0;} .mx-auto{margin-left:auto;margin-right:auto;} -.mt-2{margin-top:0.5rem;} .mt-4{margin-top:1rem;} .mt-6{margin-top:1.5rem;} .inline-block{display:inline-block;} @@ -37,11 +36,9 @@ .flex-1{flex:1 1 0%;} .flex-row{flex-direction:row;} .flex-col{flex-direction:column;} -.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));} .cursor-default{cursor:default;} .cursor-pointer{cursor:pointer;} .select-none{-webkit-user-select:none;user-select:none;} -.list-disc{list-style-type:disc;} .list-none{list-style-type:none;} .items-center{align-items:center;} .justify-between{justify-content:space-between;} @@ -86,12 +83,10 @@ .py-1{padding-top:0.25rem;padding-bottom:0.25rem;} .py-1\.5{padding-top:0.375rem;padding-bottom:0.375rem;} .py-2{padding-top:0.5rem;padding-bottom:0.5rem;} -.pl-5{padding-left:1.25rem;} .text-center{text-align:center;} .text-left{text-align:left;} .text-2xl{font-size:1.5rem;line-height:2rem;} .text-sm{font-size:0.875rem;line-height:1.25rem;} -.text-xl{font-size:1.25rem;line-height:1.75rem;} .text-xs{font-size:0.75rem;line-height:1rem;} .font-bold{font-weight:700;} .font-medium{font-weight:500;} @@ -110,7 +105,6 @@ .focus\:ring-2:focus{--un-ring-width:2px;--un-ring-offset-shadow:var(--un-ring-inset) 0 0 0 var(--un-ring-offset-width) var(--un-ring-offset-color);--un-ring-shadow:var(--un-ring-inset) 0 0 0 calc(var(--un-ring-width) + var(--un-ring-offset-width)) var(--un-ring-color);box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);} .focus\:ring-blue-500:focus{--un-ring-opacity:1;--un-ring-color:rgba(59,130,246,var(--un-ring-opacity));} .focus\:ring-opacity-50:focus{--un-ring-opacity:0.5;} -.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;} @media (min-width: 768px){ .md\:block{display:block;} .md\:w-40{width:10rem;} @@ -118,8 +112,7 @@ .md\:text-4xl{font-size:2.25rem;line-height:2.5rem;} } @media (min-width: 1024px){ -.lg\:w-1\/2{width:50%;} -.lg\:w-1\/4{width:25%;} +.lg\:w-2\/4{width:50%;} .lg\:w-48{width:12rem;} .lg\:flex-row{flex-direction:row;} .lg\:p-4{padding:1rem;}