mirror of https://github.com/encounter/objdiff.git
Auto-detect MIPS ABI/category & add config
Under Diff Options -> Arch Settings, one can override the ABI/instruction category
This commit is contained in:
parent
e254af5acf
commit
9e57a66a05
|
@ -3081,7 +3081,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
|
@ -3100,7 +3100,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
@ -3123,11 +3123,12 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"similar",
|
"similar",
|
||||||
|
"strum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -3157,6 +3158,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shell-escape",
|
"shell-escape",
|
||||||
|
"strum",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"time",
|
"time",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.70"
|
rust-version = "1.70"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
|
|
|
@ -821,8 +821,10 @@ impl FunctionDiffUi {
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
let config = diff::DiffObjConfig {
|
let config = diff::DiffObjConfig {
|
||||||
relax_reloc_diffs: self.relax_reloc_diffs,
|
relax_reloc_diffs: self.relax_reloc_diffs,
|
||||||
space_between_args: true, // TODO
|
space_between_args: true, // TODO
|
||||||
x86_formatter: Default::default(), // TODO
|
x86_formatter: Default::default(), // TODO
|
||||||
|
mips_abi: Default::default(), // TODO
|
||||||
|
mips_instr_category: Default::default(), // TODO
|
||||||
};
|
};
|
||||||
let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), prev.as_ref())?;
|
let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), prev.as_ref())?;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.70"
|
rust-version = "1.70"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
|
@ -31,6 +31,7 @@ num-traits = "0.2.18"
|
||||||
object = { version = "0.35.0", features = ["read_core", "std", "elf", "pe"], default-features = false }
|
object = { version = "0.35.0", features = ["read_core", "std", "elf", "pe"], default-features = false }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
similar = { version = "2.5.0", default-features = false }
|
similar = { version = "2.5.0", default-features = false }
|
||||||
|
strum = { version = "0.26.2", features = ["derive"] }
|
||||||
|
|
||||||
# config
|
# config
|
||||||
globset = { version = "0.4.14", features = ["serde1"], optional = true }
|
globset = { version = "0.4.14", features = ["serde1"], optional = true }
|
||||||
|
|
|
@ -1,29 +1,56 @@
|
||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, sync::Mutex};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use object::{elf, Endian, Endianness, File, Object, Relocation, RelocationFlags};
|
use object::{elf, Endian, Endianness, File, FileFlags, Object, Relocation, RelocationFlags};
|
||||||
use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType};
|
use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{ObjArch, ProcessCodeResult},
|
arch::{ObjArch, ProcessCodeResult},
|
||||||
diff::DiffObjConfig,
|
diff::{DiffObjConfig, MipsAbi, MipsInstrCategory},
|
||||||
obj::{ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection, SymbolRef},
|
obj::{ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection, SymbolRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn configure_rabbitizer() {
|
static RABBITIZER_MUTEX: Mutex<()> = Mutex::new(());
|
||||||
|
|
||||||
|
fn configure_rabbitizer(abi: Abi) {
|
||||||
unsafe {
|
unsafe {
|
||||||
config::RabbitizerConfig_Cfg.reg_names.fpr_abi_names = Abi::O32;
|
config::RabbitizerConfig_Cfg.reg_names.fpr_abi_names = abi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ObjArchMips {
|
pub struct ObjArchMips {
|
||||||
pub endianness: Endianness,
|
pub endianness: Endianness,
|
||||||
|
pub abi: Abi,
|
||||||
|
pub instr_category: InstrCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EF_MIPS_ABI: u32 = 0x0000F000;
|
||||||
|
const EF_MIPS_MACH: u32 = 0x00FF0000;
|
||||||
|
|
||||||
|
const E_MIPS_MACH_ALLEGREX: u32 = 0x00840000;
|
||||||
|
const E_MIPS_MACH_5900: u32 = 0x00920000;
|
||||||
|
|
||||||
impl ObjArchMips {
|
impl ObjArchMips {
|
||||||
pub fn new(object: &File) -> Result<Self> {
|
pub fn new(object: &File) -> Result<Self> {
|
||||||
configure_rabbitizer();
|
let mut abi = Abi::NUMERIC;
|
||||||
Ok(Self { endianness: object.endianness() })
|
let mut instr_category = InstrCategory::CPU;
|
||||||
|
match object.flags() {
|
||||||
|
FileFlags::None => {}
|
||||||
|
FileFlags::Elf { e_flags, .. } => {
|
||||||
|
abi = match e_flags & EF_MIPS_ABI {
|
||||||
|
elf::EF_MIPS_ABI_O32 => Abi::O32,
|
||||||
|
elf::EF_MIPS_ABI_EABI32 | elf::EF_MIPS_ABI_EABI64 => Abi::N32,
|
||||||
|
_ => Abi::NUMERIC,
|
||||||
|
};
|
||||||
|
instr_category = match e_flags & EF_MIPS_MACH {
|
||||||
|
E_MIPS_MACH_ALLEGREX => InstrCategory::R4000ALLEGREX,
|
||||||
|
E_MIPS_MACH_5900 => InstrCategory::R5900,
|
||||||
|
_ => InstrCategory::CPU,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => bail!("Unsupported MIPS file flags"),
|
||||||
|
}
|
||||||
|
Ok(Self { endianness: object.endianness(), abi, instr_category })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +66,22 @@ impl ObjArch for ObjArchMips {
|
||||||
let code = §ion.data
|
let code = §ion.data
|
||||||
[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize];
|
[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize];
|
||||||
|
|
||||||
|
let _guard = RABBITIZER_MUTEX.lock().map_err(|e| anyhow!("Failed to lock mutex: {e}"))?;
|
||||||
|
configure_rabbitizer(match config.mips_abi {
|
||||||
|
MipsAbi::Auto => self.abi,
|
||||||
|
MipsAbi::O32 => Abi::O32,
|
||||||
|
MipsAbi::N32 => Abi::N32,
|
||||||
|
MipsAbi::N64 => Abi::N64,
|
||||||
|
});
|
||||||
|
let instr_category = match config.mips_instr_category {
|
||||||
|
MipsInstrCategory::Auto => self.instr_category,
|
||||||
|
MipsInstrCategory::Cpu => InstrCategory::CPU,
|
||||||
|
MipsInstrCategory::Rsp => InstrCategory::RSP,
|
||||||
|
MipsInstrCategory::R3000Gte => InstrCategory::R3000GTE,
|
||||||
|
MipsInstrCategory::R4000Allegrex => InstrCategory::R4000ALLEGREX,
|
||||||
|
MipsInstrCategory::R5900 => InstrCategory::R5900,
|
||||||
|
};
|
||||||
|
|
||||||
let start_address = symbol.address;
|
let start_address = symbol.address;
|
||||||
let end_address = symbol.address + symbol.size;
|
let end_address = symbol.address + symbol.size;
|
||||||
let ins_count = code.len() / 4;
|
let ins_count = code.len() / 4;
|
||||||
|
@ -48,7 +91,7 @@ impl ObjArch for ObjArchMips {
|
||||||
for chunk in code.chunks_exact(4) {
|
for chunk in code.chunks_exact(4) {
|
||||||
let reloc = section.relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
let reloc = section.relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
||||||
let code = self.endianness.read_u32_bytes(chunk.try_into()?);
|
let code = self.endianness.read_u32_bytes(chunk.try_into()?);
|
||||||
let instruction = Instruction::new(code, cur_addr, InstrCategory::CPU);
|
let instruction = Instruction::new(code, cur_addr, instr_category);
|
||||||
|
|
||||||
let formatted = instruction.disassemble(None, 0);
|
let formatted = instruction.disassemble(None, 0);
|
||||||
let op = instruction.unique_id as u16;
|
let op = instruction.unique_id as u16;
|
||||||
|
|
|
@ -17,15 +17,82 @@ mod code;
|
||||||
mod data;
|
mod data;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
#[derive(
|
||||||
|
Debug,
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
Default,
|
||||||
|
Eq,
|
||||||
|
PartialEq,
|
||||||
|
serde::Deserialize,
|
||||||
|
serde::Serialize,
|
||||||
|
strum::VariantArray,
|
||||||
|
strum::EnumMessage,
|
||||||
|
)]
|
||||||
pub enum X86Formatter {
|
pub enum X86Formatter {
|
||||||
#[default]
|
#[default]
|
||||||
|
#[strum(message = "Intel (default)")]
|
||||||
Intel,
|
Intel,
|
||||||
|
#[strum(message = "AT&T")]
|
||||||
Gas,
|
Gas,
|
||||||
|
#[strum(message = "NASM")]
|
||||||
Nasm,
|
Nasm,
|
||||||
|
#[strum(message = "MASM")]
|
||||||
Masm,
|
Masm,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Debug,
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
Default,
|
||||||
|
Eq,
|
||||||
|
PartialEq,
|
||||||
|
serde::Deserialize,
|
||||||
|
serde::Serialize,
|
||||||
|
strum::VariantArray,
|
||||||
|
strum::EnumMessage,
|
||||||
|
)]
|
||||||
|
pub enum MipsAbi {
|
||||||
|
#[default]
|
||||||
|
#[strum(message = "Auto (default)")]
|
||||||
|
Auto,
|
||||||
|
#[strum(message = "O32")]
|
||||||
|
O32,
|
||||||
|
#[strum(message = "N32")]
|
||||||
|
N32,
|
||||||
|
#[strum(message = "N64")]
|
||||||
|
N64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Debug,
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
Default,
|
||||||
|
Eq,
|
||||||
|
PartialEq,
|
||||||
|
serde::Deserialize,
|
||||||
|
serde::Serialize,
|
||||||
|
strum::VariantArray,
|
||||||
|
strum::EnumMessage,
|
||||||
|
)]
|
||||||
|
pub enum MipsInstrCategory {
|
||||||
|
#[default]
|
||||||
|
#[strum(message = "Auto (default)")]
|
||||||
|
Auto,
|
||||||
|
#[strum(message = "CPU")]
|
||||||
|
Cpu,
|
||||||
|
#[strum(message = "RSP (N64)")]
|
||||||
|
Rsp,
|
||||||
|
#[strum(message = "R3000 GTE (PS1)")]
|
||||||
|
R3000Gte,
|
||||||
|
#[strum(message = "R4000 ALLEGREX (PSP)")]
|
||||||
|
R4000Allegrex,
|
||||||
|
#[strum(message = "R5900 EE (PS2)")]
|
||||||
|
R5900,
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn default_true() -> bool { true }
|
const fn default_true() -> bool { true }
|
||||||
|
|
||||||
|
@ -35,7 +102,11 @@ pub struct DiffObjConfig {
|
||||||
pub relax_reloc_diffs: bool,
|
pub relax_reloc_diffs: bool,
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub space_between_args: bool,
|
pub space_between_args: bool,
|
||||||
|
// x86
|
||||||
pub x86_formatter: X86Formatter,
|
pub x86_formatter: X86Formatter,
|
||||||
|
// MIPS
|
||||||
|
pub mips_abi: MipsAbi,
|
||||||
|
pub mips_instr_category: MipsInstrCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiffObjConfig {
|
impl DiffObjConfig {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.70"
|
rust-version = "1.70"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
|
@ -46,6 +46,7 @@ ron = "0.8.1"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1.0.116"
|
serde_json = "1.0.116"
|
||||||
shell-escape = "0.1.5"
|
shell-escape = "0.1.5"
|
||||||
|
strum = { version = "0.26.2", features = ["derive"] }
|
||||||
tempfile = "3.10.1"
|
tempfile = "3.10.1"
|
||||||
time = { version = "0.3.36", features = ["formatting", "local-offset"] }
|
time = { version = "0.3.36", features = ["formatting", "local-offset"] }
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ use crate::{
|
||||||
views::{
|
views::{
|
||||||
appearance::{appearance_window, Appearance},
|
appearance::{appearance_window, Appearance},
|
||||||
config::{
|
config::{
|
||||||
config_ui, diff_config_window, project_window, ConfigViewState, CONFIG_DISABLED_TEXT,
|
arch_config_window, config_ui, project_window, ConfigViewState, CONFIG_DISABLED_TEXT,
|
||||||
},
|
},
|
||||||
data_diff::data_diff_ui,
|
data_diff::data_diff_ui,
|
||||||
debug::debug_window,
|
debug::debug_window,
|
||||||
|
@ -52,7 +52,7 @@ pub struct ViewState {
|
||||||
pub show_appearance_config: bool,
|
pub show_appearance_config: bool,
|
||||||
pub show_demangle: bool,
|
pub show_demangle: bool,
|
||||||
pub show_project_config: bool,
|
pub show_project_config: bool,
|
||||||
pub show_diff_config: bool,
|
pub show_arch_config: bool,
|
||||||
pub show_debug: bool,
|
pub show_debug: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ impl eframe::App for App {
|
||||||
show_appearance_config,
|
show_appearance_config,
|
||||||
show_demangle,
|
show_demangle,
|
||||||
show_project_config,
|
show_project_config,
|
||||||
show_diff_config,
|
show_arch_config,
|
||||||
show_debug,
|
show_debug,
|
||||||
} = view_state;
|
} = view_state;
|
||||||
|
|
||||||
|
@ -468,8 +468,8 @@ impl eframe::App for App {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.menu_button("Diff Options", |ui| {
|
ui.menu_button("Diff Options", |ui| {
|
||||||
if ui.button("More…").clicked() {
|
if ui.button("Arch Settings…").clicked() {
|
||||||
*show_diff_config = !*show_diff_config;
|
*show_arch_config = !*show_arch_config;
|
||||||
ui.close_menu();
|
ui.close_menu();
|
||||||
}
|
}
|
||||||
let mut config = config.write().unwrap();
|
let mut config = config.write().unwrap();
|
||||||
|
@ -541,7 +541,7 @@ impl eframe::App for App {
|
||||||
project_window(ctx, config, show_project_config, config_state, appearance);
|
project_window(ctx, config, show_project_config, config_state, appearance);
|
||||||
appearance_window(ctx, show_appearance_config, appearance);
|
appearance_window(ctx, show_appearance_config, appearance);
|
||||||
demangle_window(ctx, show_demangle, demangle_state, appearance);
|
demangle_window(ctx, show_demangle, demangle_state, appearance);
|
||||||
diff_config_window(ctx, config, show_diff_config, appearance);
|
arch_config_window(ctx, config, show_arch_config, appearance);
|
||||||
debug_window(ctx, show_debug, frame_history, appearance);
|
debug_window(ctx, show_debug, frame_history, appearance);
|
||||||
|
|
||||||
self.post_update(ctx);
|
self.post_update(ctx);
|
||||||
|
|
|
@ -16,9 +16,10 @@ use egui::{
|
||||||
use globset::Glob;
|
use globset::Glob;
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
config::{ProjectObject, DEFAULT_WATCH_PATTERNS},
|
config::{ProjectObject, DEFAULT_WATCH_PATTERNS},
|
||||||
diff::X86Formatter,
|
diff::{MipsAbi, MipsInstrCategory, X86Formatter},
|
||||||
};
|
};
|
||||||
use self_update::cargo_crate_version;
|
use self_update::cargo_crate_version;
|
||||||
|
use strum::{EnumMessage, VariantArray};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{AppConfig, AppConfigRef, ObjectConfig},
|
app::{AppConfig, AppConfigRef, ObjectConfig},
|
||||||
|
@ -842,29 +843,28 @@ fn split_obj_config_ui(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_config_window(
|
pub fn arch_config_window(
|
||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
config: &AppConfigRef,
|
config: &AppConfigRef,
|
||||||
show: &mut bool,
|
show: &mut bool,
|
||||||
appearance: &Appearance,
|
appearance: &Appearance,
|
||||||
) {
|
) {
|
||||||
let mut config_guard = config.write().unwrap();
|
let mut config_guard = config.write().unwrap();
|
||||||
egui::Window::new("Diff Config").open(show).show(ctx, |ui| {
|
egui::Window::new("Arch Settings").open(show).show(ctx, |ui| {
|
||||||
diff_config_ui(ui, &mut config_guard, appearance);
|
arch_config_ui(ui, &mut config_guard, appearance);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_config_ui(ui: &mut egui::Ui, config: &mut AppConfig, _appearance: &Appearance) {
|
fn arch_config_ui(ui: &mut egui::Ui, config: &mut AppConfig, _appearance: &Appearance) {
|
||||||
egui::ComboBox::new("x86_formatter", "X86 Format")
|
ui.heading("x86");
|
||||||
.selected_text(format!("{:?}", config.diff_obj_config.x86_formatter))
|
egui::ComboBox::new("x86_formatter", "Format")
|
||||||
|
.selected_text(config.diff_obj_config.x86_formatter.get_message().unwrap())
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
for &formatter in
|
for &formatter in X86Formatter::VARIANTS {
|
||||||
&[X86Formatter::Intel, X86Formatter::Gas, X86Formatter::Nasm, X86Formatter::Masm]
|
|
||||||
{
|
|
||||||
if ui
|
if ui
|
||||||
.selectable_label(
|
.selectable_label(
|
||||||
config.diff_obj_config.x86_formatter == formatter,
|
config.diff_obj_config.x86_formatter == formatter,
|
||||||
format!("{:?}", formatter),
|
formatter.get_message().unwrap(),
|
||||||
)
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -873,4 +873,38 @@ fn diff_config_ui(ui: &mut egui::Ui, config: &mut AppConfig, _appearance: &Appea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.separator();
|
||||||
|
ui.heading("MIPS");
|
||||||
|
egui::ComboBox::new("mips_abi", "ABI")
|
||||||
|
.selected_text(config.diff_obj_config.mips_abi.get_message().unwrap())
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
for &abi in MipsAbi::VARIANTS {
|
||||||
|
if ui
|
||||||
|
.selectable_label(
|
||||||
|
config.diff_obj_config.mips_abi == abi,
|
||||||
|
abi.get_message().unwrap(),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
config.diff_obj_config.mips_abi = abi;
|
||||||
|
config.queue_reload = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
egui::ComboBox::new("mips_instr_category", "Instruction Category")
|
||||||
|
.selected_text(config.diff_obj_config.mips_instr_category.get_message().unwrap())
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
for &category in MipsInstrCategory::VARIANTS {
|
||||||
|
if ui
|
||||||
|
.selectable_label(
|
||||||
|
config.diff_obj_config.mips_instr_category == category,
|
||||||
|
category.get_message().unwrap(),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
config.diff_obj_config.mips_instr_category = category;
|
||||||
|
config.queue_reload = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue