Only fix the fn update function for this error.
use eframe::{egui, Theme};
use egui::{Color32, RichText};
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

use capstone::prelude::*;
use goblin::Object;
use rfd::FileDialog;

use petgraph::graph::Graph;
use petgraph::dot::{Dot, Config};

#[derive(PartialEq, Clone, Debug)]
enum Architecture {
    X86,
    X86_64,
    ARM,
    ARM64,
}

#[derive(Clone)]
struct BinaryAnalyzerApp {
    instructions: Vec<Instruction>,
    error_message: Option<String>,
    arch: Architecture,
    file_path: Option<String>,
    search_query: String,
    filtered_instructions: Vec<Instruction>,
    sections: Vec<Section>,
    symbols: Vec<Symbol>,
    selected_instruction: Option<Instruction>,
    disassembly_options: DisassemblyOptions,
    // New fields for hex dump
    show_hex_dump: bool,
    hex_dump_bytes: Vec<u8>,
    hex_dump_section_name: String,
    // New fields for CFG
    show_cfg: bool,
    cfg_dot_representation: String,
}

#[derive(Clone)]
struct Instruction {
    address: u64,
    bytes: Vec<u8>,
    mnemonic: String,
    op_str: String,
}

#[derive(Clone)]
struct Section {
    name: String,
    start: u64,
    size: u64,
    bytes: Vec<u8>,
    flags: Option<u64>,          // Section permissions/flags
    entropy: Option<f64>,        // Entropy for the section
    section_type: Option<String>,// Type of the section
}

#[derive(Clone)]
struct Symbol {
    name: String,
    address: u64,
}

#[derive(Default, Clone)]
struct DisassemblyOptions {
    show_bytes: bool,
    syntax: SyntaxPreference,
}

#[derive(PartialEq, Clone, Default)]
enum SyntaxPreference {
    #[default]
    Intel,
    Att,
}

impl Default for BinaryAnalyzerApp {
    fn default() -> Self {
        Self {
            instructions: Vec::new(),
            error_message: None,
            arch: Architecture::X86, // Default to x86
            file_path: None,
            search_query: String::new(),
            filtered_instructions: Vec::new(),
            sections: Vec::new(),
            symbols: Vec::new(),
            selected_instruction: None,
            disassembly_options: DisassemblyOptions::default(),
            show_hex_dump: false,
            hex_dump_bytes: Vec::new(),
            hex_dump_section_name: String::new(),
            show_cfg: false,
            cfg_dot_representation: String::new(),
        }
    }
}

impl eframe::App for BinaryAnalyzerApp {
    fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
        // Top panel for header
        egui::TopBottomPanel::top("header").show(ctx, |ui| {
            ui.horizontal(|ui| {
                ui.heading("Advanced Binary Analyzer");
            });
        });

        // Left panel for controls
        egui::SidePanel::left("controls_panel")
            .resizable(true)
            .default_width(250.0)
            .show(ctx, |ui| {
                ui.group(|ui| {
                    ui.heading("Controls");

                    if ui.button("Load Binary").clicked() {
                        self.load_binary();
                    }

                    ui.separator();

                    ui.label("Architecture:");
                    egui::ComboBox::from_id_source("arch_select")
                        .selected_text(format!("{:?}", self.arch))
                        .show_ui(ui, |ui| {
                            ui.selectable_value(&mut self.arch, Architecture::X86, "x86 (32-bit)");
                            ui.selectable_value(&mut self.arch, Architecture::X86_64, "x86_64 (64-bit)");
                            ui.selectable_value(&mut self.arch, Architecture::ARM, "ARM (32-bit)");
                            ui.selectable_value(&mut self.arch, Architecture::ARM64, "ARM64 (64-bit)");
                        });

                    if ui.button("Update Disassembly").clicked() {
                        self.update_disassembly();
                    }

                    ui.separator();

                    ui.label("Search Instructions:");
                    if ui.text_edit_singleline(&mut self.search_query).changed() {
                        self.update_filtered_instructions();
                    }

                    ui.separator();

                    ui.collapsing("Disassembly Options", |ui| {
                        ui.checkbox(&mut self.disassembly_options.show_bytes, "Show Bytes");
                        ui.label("Syntax:");
                        ui.horizontal(|ui| {
                            ui.radio_value(
                                &mut self.disassembly_options.syntax,
                                SyntaxPreference::Intel,
                                "Intel",
                            );
                            ui.radio_value(
                                &mut self.disassembly_options.syntax,
                                SyntaxPreference::Att,
                                "AT&T",
                            );
                        });
                    });

                    ui.separator();

                    if ui.button("Export Disassembly").clicked() {
                        self.export_disassembly();
                    }

                    ui.separator();

                    if ui.button("Generate CFG").clicked() {
                        self.generate_cfg();
                        self.show_cfg = true;
                    }
                });

                if let Some(error) = &self.error_message {
                    ui.add_space(10.0);
                    ui.group(|ui| {
                        ui.colored_label(Color32::RED, error);
                    });
                }
            });

        // Right panel for sections and symbols
        egui::SidePanel::right("side_panel")
        .resizable(true)
        .default_width(250.0)
        .show(ctx, |ui| {
            ui.collapsing("Sections", |ui| {
                egui::ScrollArea::vertical().show(ui, |ui| {
                    for section in &self.sections {
                        let section_name = &section.name;
                        let section_start = section.start;
                        let section_size = section.size;
                        let section_flags = section.flags;
                        let section_type = section.section_type.as_ref();
                        let section_entropy = section.entropy;
                        let section_bytes = &section.bytes;
                        ui.collapsing(section_name, |ui| {
                            ui.label(format!("Address: 0x{:08x}", section_start));
                            ui.label(format!("Size: {} bytes", section_size));
                            if let Some(flags) = section_flags {
                                ui.label(format!("Flags: 0x{:08x}", flags));
                            }
                            if let Some(section_type) = section_type {
                                ui.label(format!("Type: {}", section_type));
                            }
                            if let Some(entropy) = section_entropy {
                                ui.label(format!("Entropy: {:.4}", entropy));
                            }
                            if ui.button("View Hex Dump").clicked() {
                                self.view_hex_dump(&section_bytes[..], section_name);
                            }
                        }); 
                    }
                });
            });

                ui.separator();

                ui.collapsing("Symbols", |ui| {
                    egui::ScrollArea::vertical().show(ui, |ui| {
                        for symbol in &self.symbols {
                            ui.label(format!(
                                "{} - 0x{:08x}",
                                symbol.name, symbol.address
                            ));
                        }
                    });
                });
            });

        // Central panel for disassembly
        egui::CentralPanel::default().show(ctx, |ui| {
            if let Some(path) = &self.file_path {
                ui.horizontal(|ui| {
                    ui.label("Loaded File:");
                    ui.monospace(path);
                });
            }

            ui.separator();

            ui.heading("Disassembled Instructions");
            egui::ScrollArea::both().show(ui, |ui| {
                egui::Grid::new("disassembly_grid")
                    .striped(true)
                    .show(ui, |ui| {
                        for instruction in &self.filtered_instructions {
                            ui.horizontal(|ui| {
                                let addr = format!("0x{:08x}", instruction.address);
                                if ui
                                    .selectable_label(
                                        self.selected_instruction
                                            .as_ref()
                                            .map_or(false, |instr| instr.address == instruction.address),
                                        &addr,
                                    )
                                    .clicked()
                                {
                                    self.selected_instruction = Some(instruction.clone());
                                }

                                if self.disassembly_options.show_bytes {
                                    let bytes_str = instruction
                                        .bytes
                                        .iter()
                                        .map(|b| format!("{:02x}", b))
                                        .collect::<Vec<_>>()
                                        .join(" ");
                                    ui.label(bytes_str);
                                }

                                // Syntax Highlighting
                                let mnemonic = RichText::new(&instruction.mnemonic)
                                    .color(Color32::LIGHT_BLUE);
                                ui.label(mnemonic);
                                ui.label(&instruction.op_str);
                            });
                            ui.end_row();
                        }
                    });
            });

            ui.separator();

            if let Some(instruction) = &self.selected_instruction {
                ui.group(|ui| {
                    ui.heading("Instruction Details");
                    ui.label(format!("Address: 0x{:08x}", instruction.address));
                    ui.label(format!("Bytes: {:?}", instruction.bytes));
                    ui.label(format!("Mnemonic: {}", instruction.mnemonic));
                    ui.label(format!("Operands: {}", instruction.op_str));
                    // More detailed information can be added here
                });
            }
        });

        // Hex Dump Window
        if self.show_hex_dump {
            let title = format!("Hex Dump - {}", self.hex_dump_section_name);
            let hex_string = self.format_hex_dump(&self.hex_dump_bytes);
            egui::Window::new(title)
                .resizable(true)
                .vscroll(true)
                .hscroll(true)
                .open(&mut self.show_hex_dump)
                .show(ctx, |ui| {
                    // Display hex dump
                    ui.monospace(&hex_string);
                });
        }

        // Control Flow Graph Visualization
        if self.show_cfg {
            let cfg_dot = self.cfg_dot_representation.clone();
            egui::Window::new("Control Flow Graph")
                .resizable(true)
                .vscroll(true)
                .hscroll(true)
                .open(&mut self.show_cfg)
                .show(ctx, |ui| {
                    ui.label("Control Flow Graph (DOT format):");
                    egui::ScrollArea::vertical().show(ui, |ui| {
                        ui.code(&cfg_dot);
                    });
                    // Actual graph visualization can be implemented with additional libraries
                });
        }
    }
}

impl BinaryAnalyzerApp {
    fn load_binary(&mut self) {
        self.error_message = None; // Clear previous errors
        self.instructions.clear();
        self.filtered_instructions.clear();
        self.sections.clear();
        self.symbols.clear();

        if let Some(path) = FileDialog::new()
            .add_filter("Executable Files", &["exe", "bin", "out", "elf"])
            .pick_file()
        {
            self.file_path = Some(path.display().to_string());
            match File::open(&path) {
                Ok(mut file) => {
                    let mut buffer = Vec::new();
                    if let Err(e) = file.read_to_end(&mut buffer) {
                        self.error_message = Some(format!("Failed to read file: {}", e));
                        return;
                    }

                    // Use goblin to parse the binary format
                    match Object::parse(&buffer) {
                        Ok(object) => {
                            match object {
                                Object::Elf(elf) => {
                                    self.arch = if elf.is_64 {
                                        Architecture::X86_64
                                    } else {
                                        Architecture::X86
                                    };
                                    let entry = elf.entry;
                                    self.sections = elf
                                        .section_headers
                                        .iter()
                                        .filter(|s| s.sh_size > 0)
                                        .map(|s| {
                                            let name = elf.shdr_strtab.get_at(s.sh_name).unwrap_or("").to_string();
                                            let bytes = buffer[s.file_range().unwrap()].to_vec();
                                            let mut section = Section {
                                                name,
                                                start: s.sh_addr,
                                                size: s.sh_size,
                                                bytes,
                                                flags: Some(s.sh_flags),
                                                entropy: None,
                                                section_type: Some(format!("{:?}", s.sh_type)),
                                            };
                                            section.entropy = Some(section.calculate_entropy());
                                            section
                                        })
                                        .collect::<Vec<_>>();
                                    self.symbols = elf
                                        .syms
                                        .iter()
                                        .map(|sym| Symbol {
                                            name: elf.strtab.get_at(sym.st_name).unwrap_or("").to_string(),
                                            address: sym.st_value,
                                        })
                                        .collect();

                                    self.disassemble();
                                }
                                Object::PE(pe) => {
                                    self.arch = if pe.is_64 {
                                        Architecture::X86_64
                                    } else {
                                        Architecture::X86
                                    };
                                    let entry = pe.entry as u64;
                                    self.sections = pe
                                        .sections
                                        .iter()
                                        .map(|s| {
                                            let name = String::from_utf8_lossy(&s.name[..]).trim_end_matches('\u{0}').to_string();
                                            let bytes = buffer[s.pointer_to_raw_data as usize..(s.pointer_to_raw_data + s.size_of_raw_data) as usize].to_vec();
                                            let mut section = Section {
                                                name,
                                                start: s.virtual_address as u64,
                                                size: s.virtual_size as u64,
                                                bytes,
                                                flags: Some(s.characteristics as u64),
                                                entropy: None,
                                                section_type: None,
                                            };
                                            section.entropy = Some(section.calculate_entropy());
                                            section
                                        })
                                        .collect::<Vec<_>>();
                                    self.symbols = vec![]; // PE symbol parsing can be added here

                                    self.disassemble();
                                }
                                Object::Mach(_mach) => {
                                    self.error_message = Some("Mach-O binaries are not supported yet.".to_string());
                                }
                                _ => {
                                    self.error_message = Some("Unsupported binary format".to_string());
                                }
                            }
                        }
                        Err(e) => {
                            self.error_message = Some(format!("Failed to parse binary: {}", e));
                        }
                    }
                }
                Err(e) => {
                    self.error_message = Some(format!("Failed to open file: {}", e));
                }
            }
        }
    }

    fn disassemble(&mut self) {
        let cs = match self.create_capstone() {
            Ok(cs) => cs,
            Err(e) => {
                self.error_message = Some(format!("Capstone error: {}", e));
                return;
            }
        };

        let code_section = self.sections.iter().find(|s| s.name == ".text");
        if let Some(text_section) = code_section {
            match cs.disasm_all(&text_section.bytes, text_section.start) {
                Ok(insns) => {
                    self.instructions.clear();
                    for i in insns.iter() {
                        let instruction = Instruction {
                            address: i.address(),
                            bytes: i.bytes().to_vec(),
                            mnemonic: i.mnemonic().unwrap_or("").to_string(),
                            op_str: i.op_str().unwrap_or("").to_string(),
                        };
                        self.instructions.push(instruction);
                    }
                    self.update_filtered_instructions();
                }
                Err(e) => {
                    self.error_message = Some(format!("Disassembly error: {}", e));
                }
            };
        } else {
            self.error_message = Some("Failed to find .text section".to_string());
        }
    }

    fn create_capstone(&self) -> Result<Capstone, capstone::Error> {
        let syntax = match self.disassembly_options.syntax {
            SyntaxPreference::Intel => arch::x86::ArchSyntax::Intel,
            SyntaxPreference::Att => arch::x86::ArchSyntax::Att,
        };
        match self.arch {
            Architecture::X86 => Capstone::new()
                .x86()
                .mode(arch::x86::ArchMode::Mode32)
                .syntax(syntax)
                .detail(true)
                .build(),
            Architecture::X86_64 => Capstone::new()
                .x86()
                .mode(arch::x86::ArchMode::Mode64)
                .syntax(syntax)
                .detail(true)
                .build(),
            Architecture::ARM => Capstone::new()
                .arm()
                .mode(arch::arm::ArchMode::Arm)
                .detail(true)
                .build(),
            Architecture::ARM64 => Capstone::new()
                .arm64()
                .mode(arch::arm64::ArchMode::Arm)
                .detail(true)
                .build(),
        }
    }

    fn update_disassembly(&mut self) {
        if self.sections.is_empty() {
            self.error_message = Some("No sections available to disassemble".to_string());
            return;
        }
        self.disassemble();
    }

    fn update_filtered_instructions(&mut self) {
        if self.search_query.is_empty() {
            self.filtered_instructions = self.instructions.clone();
        } else {
            let query = self.search_query.to_lowercase();
            self.filtered_instructions = self
                .instructions
                .iter()
                .filter(|instr| {
                    instr.mnemonic.to_lowercase().contains(&query)
                        || instr.op_str.to_lowercase().contains(&query)
                })
                .cloned()
                .collect();
        }
    }

    fn view_hex_dump(&mut self, bytes: &[u8], section_name: &str) {
        self.hex_dump_bytes = bytes.to_vec();
        self.hex_dump_section_name = section_name.to_string();
        self.show_hex_dump = true;
    }

    fn format_hex_dump(&self, bytes: &[u8]) -> String {
        const BYTES_PER_LINE: usize = 16;
        let mut result = String::new();
        for (i, chunk) in bytes.chunks(BYTES_PER_LINE).enumerate() {
            let address = i * BYTES_PER_LINE;
            result.push_str(&format!("{:08x}  ", address));
            for byte in chunk {
                result.push_str(&format!("{:02x} ", byte));
            }
            // Add spacing if last line is not full
            if chunk.len() < BYTES_PER_LINE {
                for _ in 0..(BYTES_PER_LINE - chunk.len()) {
                    result.push_str("   ");
                }
            }
            result.push_str(" ");
            // ASCII representation
            for byte in chunk {
                let c = if byte.is_ascii_graphic() {
                    *byte as char
                } else {
                    '.'
                };
                result.push(c);
            }
            result.push('\n');
        }
        result
    }

    fn export_disassembly(&mut self) {
        if let Some(path) = FileDialog::new()
            .set_directory(".")
            .set_file_name("disassembly.txt")
            .save_file()
        {
            let mut content = String::new();
            for instr in &self.filtered_instructions {
                let line = format!(
                    "0x{:08x}: {}\t{}\n",
                    instr.address, instr.mnemonic, instr.op_str
                );
                content.push_str(&line);
            }
            if let Err(e) = std::fs::write(path, content) {
                self.error_message = Some(format!("Failed to export disassembly: {}", e));
            }
        }
    }

    fn generate_cfg(&mut self) {
        let basic_blocks = self.build_basic_blocks();
        let mut graph = Graph::<u64, &str>::new();
        let mut addr_to_index = HashMap::new();

        // Add nodes
        for block in &basic_blocks {
            let idx = graph.add_node(block.start_addr);
            addr_to_index.insert(block.start_addr, idx);
        }

        // Add edges
        for block in &basic_blocks {
            if let Some(&source_idx) = addr_to_index.get(&block.start_addr) {
                for &succ_addr in &block.successors {
                    if let Some(&target_idx) = addr_to_index.get(&succ_addr) {
                        graph.add_edge(source_idx, target_idx, "");
                    }
                }
            }
        }

        // Generate DOT graph
        let dot = Dot::with_config(&graph, &[Config::EdgeNoLabel]);
        self.cfg_dot_representation = format!("{}", dot);
    }

    fn build_basic_blocks(&self) -> Vec<BasicBlock> {
        let mut blocks = Vec::new();
        let mut current_block = BasicBlock {
            start_addr: 0,
            end_addr: 0,
            instructions: Vec::new(),
            successors: Vec::new(),
        };
        let mut addr_to_block = HashMap::new();

        let _addr_to_instr = self.instructions.iter().map(|instr| (instr.address, instr)).collect::<HashMap<u64, _>>();

        for instr in &self.instructions {
            if current_block.instructions.is_empty() {
                current_block.start_addr = instr.address;
            }
            current_block.instructions.push(instr.clone());
            current_block.end_addr = instr.address;

            if self.is_control_flow_instruction(instr) {
                // Handle successors
                let targets = self.get_instruction_targets(instr);
                current_block.successors = targets.clone();
                blocks.push(current_block.clone());
                addr_to_block.insert(current_block.start_addr, current_block.clone());
                current_block.instructions.clear();
            } else if self.is_block_terminator(instr) {
                blocks.push(current_block.clone());
                addr_to_block.insert(current_block.start_addr, current_block.clone());
                current_block.instructions.clear();
            }
        }
        // Add the last block if not empty
        if !current_block.instructions.is_empty() {
            blocks.push(current_block.clone());
            addr_to_block.insert(current_block.start_addr, current_block);
        }
        blocks
    }

    fn is_control_flow_instruction(&self, instr: &Instruction) -> bool {
        let mnemonic = instr.mnemonic.as_str();
        mnemonic.starts_with("j")
            || mnemonic == "call"
            || mnemonic == "jmp"
    }

    fn is_block_terminator(&self, instr: &Instruction) -> bool {
        let mnemonic = instr.mnemonic.as_str();
        mnemonic == "ret"
            || mnemonic == "hlt"
            || mnemonic == "ud2"
    }

    fn get_instruction_targets(&self, instr: &Instruction) -> Vec<u64> {
        let mnemonic = instr.mnemonic.as_str();
        let op_str = instr.op_str.as_str();
        if mnemonic == "jmp" || mnemonic.starts_with("j") {
            if let Some(target_addr) = self.parse_operand_address(op_str) {
                return vec![target_addr];
            }
        } else if mnemonic == "call" {
            if let Some(target_addr) = self.parse_operand_address(op_str) {
                return vec![instr.address + instr.bytes.len() as u64, target_addr];
            }
        }
        vec![instr.address + instr.bytes.len() as u64]
    }

    fn parse_operand_address(&self, operand: &str) -> Option<u64> {
        if operand.starts_with("0x") {
            u64::from_str_radix(&operand[2..], 16).ok()
        } else {
            operand.parse::<u64>().ok()
        }
    }
}

#[derive(Clone)]
struct BasicBlock {
    start_addr: u64,
    end_addr: u64,
    instructions: Vec<Instruction>,
    successors: Vec<u64>, // Addresses of successor blocks
}

impl Section {
    fn calculate_entropy(&self) -> f64 {
        let mut freq = [0u64; 256];
        for &byte in &self.bytes {
            freq[byte as usize] += 1;
        }
        let len = self.bytes.len() as f64;
        freq.iter().fold(0.0, |entropy, &count| {
            if count == 0 {
                entropy
            } else {
                let p = count as f64 / len;
                entropy - p * p.log2()
            }
        })
    }
}

fn main() {
    let app: BinaryAnalyzerApp = BinaryAnalyzerApp::default();
    let options = eframe::NativeOptions {
        default_theme: Theme::Dark,
        ..Default::default()
    };
    eframe::run_native("Advanced Binary Analyzer", options, Box::new(|_cc| {
        Ok(Box::new(app))
    }))
    .unwrap();
}

[{
	"resource": "/c:/Users/CISCO1/source/repos/re/src/main.rs",
	"owner": "rustc",
	"code": {
		"value": "Click for full compiler diagnostic",
		"target": {
			"$mid": 1,
			"path": "/diagnostic message [2]",
			"scheme": "rust-analyzer-diagnostics-view",
			"query": "2",
			"fragment": "file:///c%3A/Users/CISCO1/source/repos/re/src/main.rs"
		}
	},
	"severity": 8,
	"message": "cannot borrow `*self` as mutable because it is also borrowed as immutable\nmutable borrow occurs here",
	"source": "rustc",
	"startLineNumber": 203,
	"startColumn": 53,
	"endLineNumber": 203,
	"endColumn": 57,
	"relatedInformation": [
		{
			"startLineNumber": 195,
			"startColumn": 36,
			"endLineNumber": 195,
			"endColumn": 50,
			"message": "immutable borrow occurs here",
			"resource": "/c:/Users/CISCO1/source/repos/re/src/main.rs"
		},
		{
			"startLineNumber": 216,
			"startColumn": 33,
			"endLineNumber": 216,
			"endColumn": 37,
			"message": "second borrow occurs due to use of `*self` in closure",
			"resource": "/c:/Users/CISCO1/source/repos/re/src/main.rs"
		},
		{
			"startLineNumber": 195,
			"startColumn": 36,
			"endLineNumber": 195,
			"endColumn": 50,
			"message": "immutable borrow later used here",
			"resource": "/c:/Users/CISCO1/source/repos/re/src/main.rs"
		}
	]
}]