Repository: cch123/asm-cli-rust
Branch: master
Commit: 6289810f92d2
Files: 9
Total size: 25.1 KB
Directory structure:
gitextract_s1az94o5/
├── .gitignore
├── CODE_OF_CONDUCT.md
├── Cargo.toml
├── LICENSE
├── readme.md
└── src/
├── engine/
│ ├── cpu.rs
│ ├── machine.rs
│ └── mod.rs
└── main.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea/
target
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at cao1988228@163.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: Cargo.toml
================================================
[package]
name = "asm-cli-rust"
version = "0.1.0"
authors = ["Xargin <cao1988228@163.com>"]
edition = "2018"
[dependencies]
capstone = "^0.9.0"
keystone = {git = "https://github.com/keystone-engine/keystone/", rev = "18569351000cf1b8bd1ea2cc8a02c2e17b76391f"}
unicorn-engine = {git = "https://github.com/unicorn-engine/unicorn/", rev = "8fb4b45f57557eb82a165ec24ed8a2aa2f9f201b"}
hex = "0.3.2"
rustyline = "9.1.0"
ansi_term = "0.11.0"
maplit = "1"
lazy_static = "1.4.0"
clap = { version = "4.0.26", features = ["derive"] }
proc-macro2 = { version = "=1.0.93", features=["default", "proc-macro"] }
================================================
FILE: LICENSE
================================================
The Star And Thank Author License (SATA)
Copyright © 2018 Xargin(cao1988228@163.com)
Project Url: https://github.com/cch123/asm-cli-rust
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
And wait, the most important, you shall star/+1/like the project(s) in project url
section above first, and then thank the author(s) in Copyright section.
Here are some suggested ways:
- Email the authors a thank-you letter, and make friends with him/her/them.
- Report bugs or issues.
- Tell friends what a wonderful project this is.
- And, sure, you can just express thanks in your mind without telling the world.
Contributors of this project by forking have the option to add his/her name and
forked project url at copyright and project url sections, but shall not delete
or modify anything else in these two sections.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: readme.md
================================================
# Overview
this project is inspired by https://github.com/poppycompass/asmshell
## Preview

## Usage
```
shell> asm-cli-rust [x86/x64]
default : x64
optional: x86
```
key_up/key_down: history
## Build from source
1. `cargo b`
## Go version
https://github.com/cch123/asm-cli
================================================
FILE: src/engine/cpu.rs
================================================
use std::{collections::HashMap, convert::TryFrom};
use maplit::hashmap;
use unicorn_engine::{unicorn_const, RegisterX86, Unicorn};
#[derive(Clone, Copy, Debug)]
pub enum Mode {
Mode32,
Mode64,
}
#[allow(clippy::from_over_into)]
impl Into<unicorn_const::Mode> for Mode {
fn into(self) -> unicorn_const::Mode {
match self {
Self::Mode32 => unicorn_const::Mode::MODE_32,
Self::Mode64 => unicorn_const::Mode::MODE_64,
}
}
}
#[allow(clippy::from_over_into)]
impl Into<keystone::Mode> for Mode {
fn into(self) -> keystone::Mode {
match self {
Self::Mode32 => keystone::Mode::MODE_32,
Self::Mode64 => keystone::Mode::MODE_64,
}
}
}
impl TryFrom<unicorn_const::Mode> for Mode {
type Error = &'static str;
fn try_from(value: unicorn_const::Mode) -> Result<Self, Self::Error> {
match value {
unicorn_const::Mode::MODE_32 => Ok(Self::Mode32),
unicorn_const::Mode::MODE_64 => Ok(Self::Mode64),
_ => Err("unsupported mode"),
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Arch {
X86,
}
#[allow(clippy::from_over_into)]
impl Into<unicorn_const::Arch> for Arch {
fn into(self) -> unicorn_const::Arch {
match self {
Self::X86 => unicorn_const::Arch::X86,
}
}
}
#[allow(clippy::from_over_into)]
impl Into<keystone::Arch> for Arch {
fn into(self) -> keystone::Arch {
match self {
Self::X86 => keystone::Arch::X86,
}
}
}
impl TryFrom<unicorn_const::Arch> for Arch {
type Error = &'static str;
fn try_from(value: unicorn_const::Arch) -> Result<Self, Self::Error> {
match value {
unicorn_const::Arch::X86 => Ok(Self::X86),
_ => Err("unsupported arch"),
}
}
}
impl Arch {
fn dump_registers(
&self,
emu: &Unicorn<'static, ()>,
registers: HashMap<&'static str, i32>,
) -> HashMap<&'static str, u64> {
registers
.keys()
.filter(|&&x| x != "end") // "end" is pseudo-register (to add new row)
.map(|®_name| {
(
reg_name,
emu.reg_read(*registers.get(reg_name).unwrap()).unwrap(),
)
})
.collect::<HashMap<_, _>>()
}
}
pub trait ArchMeta {
fn cpu(&self) -> (Arch, Mode);
fn sp_reg(&self) -> i32;
fn fp_reg(&self) -> i32;
fn int_size(&self) -> usize;
fn sorted_reg_names(&self) -> Vec<&'static str>;
fn register_map(&self) -> HashMap<&'static str, i32>;
fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'static str, u64>;
}
#[derive(Clone, Copy, Debug)]
pub struct X32 {
inner: Arch,
}
impl X32 {
pub fn new(arch: Arch) -> Self {
Self { inner: arch }
}
}
impl ArchMeta for X32 {
fn cpu(&self) -> (Arch, Mode) {
(self.inner, Mode::Mode32)
}
fn sp_reg(&self) -> i32 {
i32::from(RegisterX86::ESP)
}
fn fp_reg(&self) -> i32 {
i32::from(RegisterX86::EBP)
}
fn int_size(&self) -> usize {
32 / 8
}
fn sorted_reg_names(&self) -> Vec<&'static str> {
vec![
"eax", "ebx", "ecx", "edx", "end", //
"esi", "edi", "end", //
"eip", "ebp", "esp", "end", //
"flags", "end", //
"cs", "ss", "ds", "es", "end", //
"fs", "gs", "end", //
]
}
fn register_map(&self) -> HashMap<&'static str, i32> {
// register to trace, display, etc.
hashmap! {
"eax" => i32::from(RegisterX86::EAX),
"ebx" => i32::from(RegisterX86::EBX),
"ecx" => i32::from(RegisterX86::ECX),
"edx" => i32::from(RegisterX86::EDX),
"esi" => i32::from(RegisterX86::ESI),
"edi" => i32::from(RegisterX86::EDI),
"eip" => i32::from(RegisterX86::EIP),
"ebp" => i32::from(RegisterX86::EBP),
"esp" => i32::from(RegisterX86::ESP),
"flags" => i32::from(RegisterX86::EFLAGS),
"cs" => i32::from(RegisterX86::CS),
"ss" => i32::from(RegisterX86::SS),
"ds" => i32::from(RegisterX86::DS),
"es" => i32::from(RegisterX86::ES),
"fs" => i32::from(RegisterX86::FS),
"gs" => i32::from(RegisterX86::GS),
}
}
fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'static str, u64> {
self.inner.dump_registers(emu, self.register_map())
}
}
#[derive(Clone, Copy, Debug)]
pub struct X64 {
inner: Arch,
}
impl X64 {
pub fn new(arch: Arch) -> X64 {
X64 { inner: arch }
}
}
impl ArchMeta for X64 {
fn cpu(&self) -> (Arch, Mode) {
(self.inner, Mode::Mode64)
}
fn sp_reg(&self) -> i32 {
i32::from(RegisterX86::RSP)
}
fn fp_reg(&self) -> i32 {
i32::from(RegisterX86::RBP)
}
fn int_size(&self) -> usize {
64 / 8
}
fn sorted_reg_names(&self) -> Vec<&'static str> {
vec![
"rax", "rbx", "rcx", "rdx", "end", //
"rsi", "rdi", "r8", "r9", "end", //
"r10", "r11", "r12", "r13", "end", //
"r14", "r15", "end", //
"rip", "rbp", "rsp", "end", //
"cs", "ss", "ds", "es", "end", //
"fs", "gs", "end", "flags", "end", //
]
}
fn register_map(&self) -> HashMap<&'static str, i32> {
// register to trace, display, etc.
hashmap! {
"rax" => i32::from(RegisterX86::RAX),
"rbx" => i32::from(RegisterX86::RBX),
"rcx" => i32::from(RegisterX86::RCX),
"rdx" => i32::from(RegisterX86::RDX),
"rsi" => i32::from(RegisterX86::RSI),
"rdi" => i32::from(RegisterX86::RDI),
"r8" => i32::from(RegisterX86::R8),
"r9" => i32::from(RegisterX86::R9),
"r10" => i32::from(RegisterX86::R10),
"r11" => i32::from(RegisterX86::R11),
"r12" => i32::from(RegisterX86::R12),
"r13" => i32::from(RegisterX86::R13),
"r14" => i32::from(RegisterX86::R14),
"r15" => i32::from(RegisterX86::R15),
"rip" => i32::from(RegisterX86::RIP),
"rbp" => i32::from(RegisterX86::RBP),
"rsp" => i32::from(RegisterX86::RSP),
"flags" => i32::from(RegisterX86::EFLAGS),
"cs" => i32::from(RegisterX86::CS),
"ss" => i32::from(RegisterX86::SS),
"ds" => i32::from(RegisterX86::DS),
"es" => i32::from(RegisterX86::ES),
"fs" => i32::from(RegisterX86::FS),
"gs" => i32::from(RegisterX86::GS),
}
}
fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'static str, u64> {
self.inner.dump_registers(emu, self.register_map())
}
}
================================================
FILE: src/engine/machine.rs
================================================
use ansi_term::Colour::{Blue, Purple, Yellow};
use keystone::{AsmResult, Error};
use std::collections::HashMap;
use unicorn_engine::unicorn_const::uc_error;
use unicorn_engine::unicorn_const::SECOND_SCALE;
use unicorn_engine::Unicorn;
use super::cpu;
#[derive(Debug)]
pub enum MachineError {
Unsupported,
Keystone(keystone::Error),
Unicorn(uc_error),
}
pub struct Machine<'a> {
pub register_map: HashMap<&'a str, i32>,
pub assembler: keystone::Keystone,
pub emu: Unicorn<'static, ()>,
pub sorted_reg_names: Vec<&'a str>,
pub byte_size: usize,
pub previous_reg_value: HashMap<&'a str, u64>,
pub cpu: (cpu::Arch, cpu::Mode),
pub sp: i32, // stack pointer
pub fp: i32, // stack frame
}
impl<'a> Machine<'a> {
pub fn new(arch: cpu::Arch, mode: cpu::Mode) -> Result<Self, MachineError> {
let emu = Self::init_unicorn(arch, mode)?;
let assembler = Self::init_keystone(arch, mode)?;
let arch_meta = Self::get_arch_meta(arch, mode)?;
let register_map = arch_meta.register_map();
let prev_reg_value = arch_meta.dump_registers(&emu);
Ok(Self {
emu,
assembler,
register_map,
sorted_reg_names: arch_meta.sorted_reg_names(),
byte_size: arch_meta.int_size(),
previous_reg_value: prev_reg_value,
cpu: arch_meta.cpu(),
sp: arch_meta.sp_reg(),
fp: arch_meta.fp_reg(),
})
}
pub fn new_from_arch(arch_name: &str) -> Result<Self, MachineError> {
let arch_meta = Self::get_arch_meta_from_name(arch_name)?;
let cpu = arch_meta.cpu();
Self::new(cpu.0, cpu.1)
}
pub(crate) fn init_unicorn(
arch: cpu::Arch,
mode: cpu::Mode,
) -> Result<Unicorn<'static, ()>, MachineError> {
Unicorn::new(arch.into(), mode.into()).map_err(MachineError::Unicorn)
}
pub(crate) fn init_keystone(
arch: cpu::Arch,
mode: cpu::Mode,
) -> Result<keystone::Keystone, MachineError> {
keystone::Keystone::new(arch.into(), mode.into()).map_err(MachineError::Keystone)
}
pub(crate) fn get_arch_name(
arch: cpu::Arch,
mode: cpu::Mode,
) -> Result<&'static str, MachineError> {
match arch {
cpu::Arch::X86 => match mode {
cpu::Mode::Mode32 => Ok("x32"),
cpu::Mode::Mode64 => Ok("x64"),
// _ => Err(MachineError::Unsupported),
},
// _ => Err(MachineError::Unsupported),
}
}
pub(crate) fn get_arch_meta(
arch: cpu::Arch,
mode: cpu::Mode,
) -> Result<Box<dyn cpu::ArchMeta>, MachineError> {
let arch_name = Self::get_arch_name(arch, mode)?;
Self::get_arch_meta_from_name(arch_name)
}
pub(crate) fn get_arch_meta_from_name(
arch_name: &str,
) -> Result<Box<dyn cpu::ArchMeta>, MachineError> {
match arch_name {
"x32" => Ok(Box::new(cpu::X32::new(cpu::Arch::X86))),
"x64" => Ok(Box::new(cpu::X64::new(cpu::Arch::X86))),
_ => Err(MachineError::Unsupported),
}
}
pub fn set_sp(&mut self, value: u64) -> Result<(), MachineError> {
self.emu
.reg_write(self.sp, value)
.map_err(MachineError::Unicorn)
}
pub fn set_fp(&mut self, value: u64) -> Result<(), MachineError> {
self.emu
.reg_write(self.fp, value)
.map_err(MachineError::Unicorn)
}
}
impl<'a> Machine<'a> {
pub fn print_machine(&self) {
println!("arch: {:?} mode: {:?}", self.cpu.0, self.cpu.1);
}
pub fn print_register(&mut self) {
println!(
"{}",
Yellow.paint("----------------- cpu context -----------------")
);
let mut current_reg_val_map = HashMap::new();
for ®_name in &self.sorted_reg_names {
if reg_name == "end" {
println!();
continue;
}
let &uc_reg = self.register_map.get(reg_name).unwrap();
// pad reg_name to 3 bytes
let mut padded_reg_name = reg_name.to_string();
while padded_reg_name.len() < 3 {
padded_reg_name.push(' ');
}
let reg_val = self.emu.reg_read(uc_reg).unwrap();
let previous_reg_val = *self.previous_reg_value.get(reg_name).unwrap();
let reg_val_str = match self.byte_size {
4 => format!("0x{:08x}", reg_val),
8 => format!("0x{:016x}", reg_val),
_ => unreachable!(),
};
if previous_reg_val != reg_val {
print!("{} : {} ", padded_reg_name, Blue.paint(reg_val_str));
} else {
print!("{} : {} ", padded_reg_name, reg_val_str);
}
current_reg_val_map.insert(reg_name, reg_val);
if reg_name == "flags" {
self.print_flags(reg_val);
}
}
self.previous_reg_value = current_reg_val_map;
}
pub fn asm(&self, str: String, address: u64) -> Result<AsmResult, Error> {
self.assembler.asm(str, address)
}
pub fn write_instruction(&mut self, byte_arr: Vec<u8>) {
let address = 0x0000;
let _ = self.emu.mem_write(address, &byte_arr);
let _ = self.emu.emu_start(
address,
address + byte_arr.len() as u64,
10 * SECOND_SCALE,
1000,
);
}
pub fn print_stack(&self) {
println!(
"{}",
Purple.paint("----------------- stack context -----------------")
);
let cur_sp_val = self.emu.reg_read(self.sp).unwrap();
//let start_address = (0x1300000 - 8 * self.byte_size) as u64;
let mut start_address: u64 = 0x1300000;
while cur_sp_val < start_address - 4 * self.byte_size as u64 {
start_address -= 4 * self.byte_size as u64;
}
start_address -= 8 * self.byte_size as u64;
let mem_data = self
.emu
.mem_read_as_vec(start_address, self.byte_size * 4 * 5)
.unwrap();
// 8 个字节打印一次
(0..mem_data.len())
.step_by(4 * self.byte_size)
.for_each(|idx| {
match self.byte_size {
4 => print!("{:08x} : ", start_address + idx as u64),
8 => print!("{:016x} : ", start_address + idx as u64),
_ => unreachable!(),
}
(0..4).for_each(|offset| {
let (start_pos, end_pos) = (
idx + offset * self.byte_size,
idx + offset * self.byte_size + self.byte_size,
);
let mut cur = mem_data[start_pos..end_pos].to_vec();
cur.reverse();
if (start_address + start_pos as u64) == cur_sp_val {
print!("{} ", Blue.paint(hex::encode(cur)));
} else {
print!("{} ", hex::encode(cur));
}
});
println!();
});
println!();
}
fn print_flags(&self, flag_val: u64) {
let flag_names = vec!["cf", "zf", "of", "sf", "pf", "af", "df"];
let name_to_bit = vec![
("cf", 0),
("pf", 2),
("af", 4),
("zf", 6),
("sf", 7),
("df", 10),
("of", 11),
]
.into_iter()
.collect::<HashMap<_, _>>();
for flag_name in flag_names {
let bit_pos = name_to_bit.get(flag_name).unwrap();
let flag_val = flag_val >> (*bit_pos as u64) & 1;
match flag_val {
0 => print!("{}({}) ", flag_name, flag_val),
1 => print!("{} ", Blue.paint(format!("{}({})", flag_name, flag_val))),
_ => unreachable!(),
}
}
}
}
================================================
FILE: src/engine/mod.rs
================================================
pub mod cpu;
pub mod machine;
================================================
FILE: src/main.rs
================================================
use ansi_term::Colour::Red;
use clap::Parser;
use keystone::{OptionType, OptionValue, Error};
use crate::engine::machine::MachineError;
use rustyline::error::ReadlineError;
use rustyline::{Cmd, Editor, KeyCode, KeyEvent, Modifiers};
use unicorn_engine::unicorn_const::Permission;
pub mod engine;
use crate::engine::machine::Machine;
#[derive(clap::ValueEnum, Clone, Debug, PartialEq)]
#[allow(clippy::upper_case_acronyms)]
enum AssemblerSyntax {
INTEL,
ATT,
GAS,
MASM,
NASM,
}
#[derive(clap::Parser, Debug)]
struct Args {
#[arg(short, long)]
arch: Option<String>,
#[arg(short, long, value_enum)]
syntax: Option<AssemblerSyntax>,
#[arg(long, default_value_t = 0x01300000)]
initial_sp: u64,
#[arg(long, default_value_t = 0x10000000)]
initial_fp: u64,
#[arg(long, default_value_t = 0)]
initial_mem_begin: u64,
#[arg(long, default_value_t = 0x20000000)]
initial_mem_size: usize,
#[arg(long, default_value_t = String::from("ALL"))]
initial_mem_prot: String,
}
fn get_machine(arch_name: String) -> Machine<'static> {
Machine::new_from_arch(arch_name.as_str()).unwrap()
}
fn parse_permission(prot: &str) -> Permission {
match prot {
"READ" => Permission::READ,
"WRITE" => Permission::WRITE,
"EXEC" => Permission::EXEC,
"NONE" => Permission::NONE,
_ => Permission::ALL,
}
}
fn main() {
// let args: Vec<String> = env::args().collect();
let args = Args::parse();
let arch_name = match args.arch {
Some(r) => r,
None => "x64".to_string(),
};
let ass_syntax = match args.syntax {
Some(syntax) => match syntax {
AssemblerSyntax::INTEL => OptionValue::SYNTAX_INTEL,
AssemblerSyntax::ATT => OptionValue::SYNTAX_ATT,
AssemblerSyntax::GAS => OptionValue::SYNTAX_GAS,
AssemblerSyntax::MASM => OptionValue::SYNTAX_MASM,
AssemblerSyntax::NASM => OptionValue::SYNTAX_NASM,
},
None => OptionValue::SYNTAX_INTEL,
};
let mut m: Machine = get_machine(arch_name);
// machine init
println!("initial: sp={:?} fp={:?}", args.initial_sp, args.initial_fp);
println!("ass_syntax: {:?}", ass_syntax);
m.set_sp(args.initial_sp)
.expect("failed to write stack pointer");
m.set_fp(args.initial_fp)
.expect("failed to write stack frame");
let mem_prot = parse_permission(&args.initial_mem_prot);
println!("permission: {:?}", mem_prot);
m.emu
.mem_map(
args.initial_mem_begin,
args.initial_mem_size,
mem_prot,
)
.expect("failed to mem map");
m.assembler
.option(OptionType::SYNTAX, ass_syntax)
.expect("failed to change assembler syntax");
m.print_machine();
m.print_register();
m.print_stack();
let mut rl = Editor::<()>::new();
rl.bind_sequence(KeyEvent(KeyCode::Down, Modifiers::NONE), Cmd::NextHistory);
rl.bind_sequence(KeyEvent(KeyCode::Up, Modifiers::NONE), Cmd::PreviousHistory);
loop {
let input = rl.readline(Red.paint(">> ").to_string().as_str());
match input {
Ok(line) => {
let result = m.asm(line.to_string(), 0);
if line.is_empty() {
println!("failed to assemble, err: {:?}", Err::<Error, MachineError>(MachineError::Unsupported));
}
match result {
Ok(r) => {
rl.add_history_entry(line.as_str());
println!(
"{} : {} {} : {}",
Red.paint("mnemonic"),
line.trim(),
Red.paint("hex"),
r
);
m.write_instruction(r.bytes);
m.print_register();
m.print_stack();
}
Err(e) => println!("failed to assemble, err: {:?}", e),
}
}
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break;
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
}
}
}
gitextract_s1az94o5/
├── .gitignore
├── CODE_OF_CONDUCT.md
├── Cargo.toml
├── LICENSE
├── readme.md
└── src/
├── engine/
│ ├── cpu.rs
│ ├── machine.rs
│ └── mod.rs
└── main.rs
SYMBOL INDEX (59 symbols across 3 files)
FILE: src/engine/cpu.rs
type Mode (line 7) | pub enum Mode {
method into (line 14) | fn into(self) -> unicorn_const::Mode {
method into (line 24) | fn into(self) -> keystone::Mode {
type Error (line 33) | type Error = &'static str;
method try_from (line 34) | fn try_from(value: unicorn_const::Mode) -> Result<Self, Self::Error> {
type Arch (line 44) | pub enum Arch {
method into (line 50) | fn into(self) -> unicorn_const::Arch {
method into (line 59) | fn into(self) -> keystone::Arch {
type Error (line 67) | type Error = &'static str;
method try_from (line 68) | fn try_from(value: unicorn_const::Arch) -> Result<Self, Self::Error> {
method dump_registers (line 77) | fn dump_registers(
type ArchMeta (line 95) | pub trait ArchMeta {
method cpu (line 96) | fn cpu(&self) -> (Arch, Mode);
method sp_reg (line 97) | fn sp_reg(&self) -> i32;
method fp_reg (line 98) | fn fp_reg(&self) -> i32;
method int_size (line 99) | fn int_size(&self) -> usize;
method sorted_reg_names (line 100) | fn sorted_reg_names(&self) -> Vec<&'static str>;
method register_map (line 101) | fn register_map(&self) -> HashMap<&'static str, i32>;
method dump_registers (line 102) | fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'stat...
method cpu (line 115) | fn cpu(&self) -> (Arch, Mode) {
method sp_reg (line 119) | fn sp_reg(&self) -> i32 {
method fp_reg (line 122) | fn fp_reg(&self) -> i32 {
method int_size (line 126) | fn int_size(&self) -> usize {
method sorted_reg_names (line 130) | fn sorted_reg_names(&self) -> Vec<&'static str> {
method register_map (line 141) | fn register_map(&self) -> HashMap<&'static str, i32> {
method dump_registers (line 163) | fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'stat...
method cpu (line 178) | fn cpu(&self) -> (Arch, Mode) {
method sp_reg (line 182) | fn sp_reg(&self) -> i32 {
method fp_reg (line 185) | fn fp_reg(&self) -> i32 {
method int_size (line 189) | fn int_size(&self) -> usize {
method sorted_reg_names (line 193) | fn sorted_reg_names(&self) -> Vec<&'static str> {
method register_map (line 205) | fn register_map(&self) -> HashMap<&'static str, i32> {
method dump_registers (line 235) | fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'stat...
type X32 (line 106) | pub struct X32 {
method new (line 110) | pub fn new(arch: Arch) -> Self {
type X64 (line 169) | pub struct X64 {
method new (line 173) | pub fn new(arch: Arch) -> X64 {
FILE: src/engine/machine.rs
type MachineError (line 11) | pub enum MachineError {
type Machine (line 17) | pub struct Machine<'a> {
function new (line 30) | pub fn new(arch: cpu::Arch, mode: cpu::Mode) -> Result<Self, MachineErro...
function new_from_arch (line 53) | pub fn new_from_arch(arch_name: &str) -> Result<Self, MachineError> {
function init_unicorn (line 59) | pub(crate) fn init_unicorn(
function init_keystone (line 66) | pub(crate) fn init_keystone(
function get_arch_name (line 73) | pub(crate) fn get_arch_name(
function get_arch_meta (line 87) | pub(crate) fn get_arch_meta(
function get_arch_meta_from_name (line 95) | pub(crate) fn get_arch_meta_from_name(
function set_sp (line 105) | pub fn set_sp(&mut self, value: u64) -> Result<(), MachineError> {
function set_fp (line 110) | pub fn set_fp(&mut self, value: u64) -> Result<(), MachineError> {
function print_machine (line 118) | pub fn print_machine(&self) {
function print_register (line 121) | pub fn print_register(&mut self) {
function asm (line 164) | pub fn asm(&self, str: String, address: u64) -> Result<AsmResult, Error> {
function write_instruction (line 168) | pub fn write_instruction(&mut self, byte_arr: Vec<u8>) {
function print_stack (line 179) | pub fn print_stack(&self) {
function print_flags (line 225) | fn print_flags(&self, flag_val: u64) {
FILE: src/main.rs
type AssemblerSyntax (line 16) | enum AssemblerSyntax {
type Args (line 25) | struct Args {
function get_machine (line 46) | fn get_machine(arch_name: String) -> Machine<'static> {
function parse_permission (line 50) | fn parse_permission(prot: &str) -> Permission {
function main (line 60) | fn main() {
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (27K chars).
[
{
"path": ".gitignore",
"chars": 14,
"preview": ".idea/\ntarget\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3350,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "Cargo.toml",
"chars": 598,
"preview": "[package]\nname = \"asm-cli-rust\"\nversion = \"0.1.0\"\nauthors = [\"Xargin <cao1988228@163.com>\"]\nedition = \"2018\"\n\n[dependenc"
},
{
"path": "LICENSE",
"chars": 1798,
"preview": "The Star And Thank Author License (SATA)\n\nCopyright © 2018 Xargin(cao1988228@163.com)\n\nProject Url: https://github.com/c"
},
{
"path": "readme.md",
"chars": 306,
"preview": "# Overview\n\nthis project is inspired by https://github.com/poppycompass/asmshell\n\n## Preview\n\n\n\n##"
},
{
"path": "src/engine/cpu.rs",
"chars": 7026,
"preview": "use std::{collections::HashMap, convert::TryFrom};\n\nuse maplit::hashmap;\nuse unicorn_engine::{unicorn_const, RegisterX86"
},
{
"path": "src/engine/machine.rs",
"chars": 8076,
"preview": "use ansi_term::Colour::{Blue, Purple, Yellow};\nuse keystone::{AsmResult, Error};\nuse std::collections::HashMap;\nuse unic"
},
{
"path": "src/engine/mod.rs",
"chars": 30,
"preview": "pub mod cpu;\npub mod machine;\n"
},
{
"path": "src/main.rs",
"chars": 4475,
"preview": "use ansi_term::Colour::Red;\nuse clap::Parser;\nuse keystone::{OptionType, OptionValue, Error};\nuse crate::engine::machine"
}
]
About this extraction
This page contains the full source code of the cch123/asm-cli-rust GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (25.1 KB), approximately 6.8k tokens, and a symbol index with 59 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.