diff --git a/bindings/java/src/main/java/keystone/natives/DirectMappingKeystoneNative.java b/bindings/java/src/main/java/keystone/natives/DirectMappingKeystoneNative.java index 5059ff1d..9083a121 100644 --- a/bindings/java/src/main/java/keystone/natives/DirectMappingKeystoneNative.java +++ b/bindings/java/src/main/java/keystone/natives/DirectMappingKeystoneNative.java @@ -81,7 +81,7 @@ private DirectMappingKeystoneNative() { * @param numberOfStatements number of statements successfully processed * @return 0 on success, or -1 on failure. */ - public static native int ks_asm(Pointer engine, String assembly, int address, PointerByReference machineCodeBuffer, + public static native int ks_asm(Pointer engine, String assembly, long address, PointerByReference machineCodeBuffer, IntByReference machineCodeSize, IntByReference numberOfStatements); /** @@ -176,4 +176,4 @@ public static native int ks_asm(Pointer engine, String assembly, int address, Po * @return An hexadecimal number as (major << 8 | minor), which encodes both major & minor versions. */ public static native int ks_version(IntByReference major, IntByReference minor); -} \ No newline at end of file +} diff --git a/bindings/python/keystone/keystone_const.py b/bindings/python/keystone/keystone_const.py index d97deb24..bbbb8ba9 100644 --- a/bindings/python/keystone/keystone_const.py +++ b/bindings/python/keystone/keystone_const.py @@ -20,6 +20,9 @@ KS_MODE_ARM = 1 KS_MODE_THUMB = 16 KS_MODE_V8 = 64 +KS_MODE_V4 = 128 +KS_MODE_XSCALE = 256 +KS_MODE_V5 = 512 KS_MODE_MICRO = 16 KS_MODE_MIPS3 = 32 KS_MODE_MIPS32R6 = 64 diff --git a/bindings/python/sample.py b/bindings/python/sample.py index 6ee9f889..6633ffea 100755 --- a/bindings/python/sample.py +++ b/bindings/python/sample.py @@ -69,7 +69,13 @@ def sym_resolver(symbol, value): test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN, b"sub r1, r2, r5") test_ks(KS_ARCH_ARM, KS_MODE_THUMB, b"movs r4, #0xf0") test_ks(KS_ARCH_ARM, KS_MODE_THUMB + KS_MODE_BIG_ENDIAN, b"movs r4, #0xf0") - + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_V4, b"nop") + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_V4, b"nop") + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_XSCALE, b"nop") + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_XSCALE, b"nop") + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_V5, b"nop") + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_V5, b"nop") + # ARM64 test_ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN, b"ldr w1, [sp, #0x8]") diff --git a/bindings/python/setup.py b/bindings/python/setup.py index cea175c8..a52f1f65 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -49,6 +49,7 @@ def copy_sources(): dir_util.copy_tree("../../llvm", "src/llvm/") dir_util.copy_tree("../../include", "src/include/") + dir_util.copy_tree("../../suite", "src/suite") src.extend(glob.glob("../../*.h")) src.extend(glob.glob("../../*.cpp")) diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index b41e5988..b612c6ca 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "keystone" -version = "0.9.1" +version = "0.10.0" authors = [ "Remco Verhoef ", "Tasuku SUENAGA a.k.a. gunyarakun " @@ -10,17 +10,17 @@ license = "GPL-2.0" readme = "README.md" repository = "https://github.com/keystone-engine/keystone" include = [ - "src/*", "tests/*", "Cargo.toml", "COPYING", "README.md", - "keystone-sys/*" + "src/*", "tests/*", "Cargo.toml", "COPYING", "README.md" ] [dependencies] -bitflags = "1.0" libc = "0.2" -keystone-sys = { path = "keystone-sys", version = "0.9.1" } +keystone-sys = { path = "keystone-sys", version = "0.10" } [features] default = [] use_system_keystone = ["keystone-sys/use_system_keystone"] build_keystone_cmake = ["keystone-sys/build_keystone_cmake"] + +[workspace] diff --git a/bindings/rust/Makefile b/bindings/rust/Makefile index 7a3f1690..05a3a388 100644 --- a/bindings/rust/Makefile +++ b/bindings/rust/Makefile @@ -9,15 +9,18 @@ package: keystone-sys/keystone cd keystone-sys && cargo package -vv cargo package -vv +# For packaging we need to embed the keystone source in the crate keystone-sys/keystone: rsync -a ../.. keystone-sys/keystone --exclude bindings --filter ":- ../../.gitignore" clean: - rm -rf target/ keystone-sys/target/ keystone-sys/keystone/ + rm -rf keystone-sys/keystone/ + cargo clean check: - cargo test +# Make sure to only use one test thread as keystone isn't thread-safe + cargo test -- --test-threads=1 gen_const: - cd .. && python const_generator.py rust + cd .. && python2 const_generator.py rust cargo fmt diff --git a/bindings/rust/README.md b/bindings/rust/README.md index 32cb7a0e..2a608ea4 100644 --- a/bindings/rust/README.md +++ b/bindings/rust/README.md @@ -39,6 +39,7 @@ If you want to use keystone already installed in the system, specify `use_system ``` [dependencies.keystone] version = "0.10.0" +default-features = false features = ["use_system_keystone"] ``` diff --git a/bindings/rust/keystone-sys/Cargo.toml b/bindings/rust/keystone-sys/Cargo.toml index f791327c..adff79f9 100644 --- a/bindings/rust/keystone-sys/Cargo.toml +++ b/bindings/rust/keystone-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "keystone-sys" -version = "0.9.0" +version = "0.10.0" authors = [ "Remco Verhoef ", "Tasuku SUENAGA a.k.a. gunyarakun " @@ -10,21 +10,17 @@ repository = "https://github.com/keystone-engine/keystone" documentation = "https://docs.rs/keystone/" license = "GPL-2.0" build = "build.rs" -exclude = [ - "keystone/build/**" -] [build-dependencies] -build-helper = "0.1" -os_type = "2.0" pkg-config = { optional = true, version = "0.3" } +cmake = { optional = true, version = "0.1" } [dependencies] bitflags = "1.0" libc = "0.2" [features] -default = [] +default = ["build_keystone_cmake"] use_system_keystone = ["pkg-config"] -build_keystone_cmake = [] +build_keystone_cmake = ["cmake"] diff --git a/bindings/rust/keystone-sys/build.rs b/bindings/rust/keystone-sys/build.rs index 2f698ab7..599fc057 100644 --- a/bindings/rust/keystone-sys/build.rs +++ b/bindings/rust/keystone-sys/build.rs @@ -1,42 +1,45 @@ +#[cfg(feature = "build_keystone_cmake")] +extern crate cmake; #[cfg(feature = "use_system_keystone")] extern crate pkg_config; -use std::env; -use std::path::PathBuf; -use std::process::Command; +#[cfg(all(not(windows), feature = "build_keystone_cmake"))] +use std::os::unix::fs::symlink; +#[cfg(all(windows, feature = "build_keystone_cmake"))] +use std::os::windows::fs::symlink_dir as symlink; -fn build_with_cmake() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let cmake_dir = PathBuf::from("keystone"); - let build_dir = cmake_dir.join("build"); +#[cfg(feature = "build_keystone_cmake")] +use std::path::Path; - if !cmake_dir.exists() { - run(Command::new("ln").arg("-s").arg("../../..").arg("keystone")); +#[cfg(feature = "build_keystone_cmake")] +fn build_with_cmake() { + if !Path::new("keystone").exists() { + // This only happens when using the crate via a `git` reference as the + // published version already embeds keystone's source. + let pwd = std::env::current_dir().unwrap(); + let keystone_dir = pwd.ancestors().skip(3).next().unwrap(); + symlink(keystone_dir, "keystone").expect("failed to symlink keystone"); } - run(Command::new("mkdir") - .current_dir(&cmake_dir) - .arg("-p") - .arg("build")); - - run(Command::new("../make-share.sh").current_dir(&build_dir)); + let dest = cmake::Config::new("keystone") + .define("BUILD_LIBS_ONLY", "1") + .define("BUILD_SHARED_LIBS", "OFF") + .define("LLVM_TARGETS_TO_BUILD", "all") + // Prevent python from leaving behind `.pyc` files which break `cargo package` + .env("PYTHONDONTWRITEBYTECODE", "1") + .build(); - run(Command::new("cmake").current_dir(&build_dir).args(&[ - &format!("-DCMAKE_INSTALL_PREFIX={}", out_dir.display()), - "-DCMAKE_BUILD_TYPE=Release", - "-DBUILD_LIBS_ONLY=1", - "-DCMAKE_OSX_ARCHITECTURES=", - "-DBUILD_SHARED_LIBS=ON", - "-DLLVM_TARGET_ARCH=host", - "-G", - "Unix Makefiles", - "..", - ])); - - run(Command::new("make").current_dir(&build_dir).arg("install")); - - println!("cargo:rustc-link-search=native={}/lib", out_dir.display()); + println!("cargo:rustc-link-search=native={}/lib", dest.display()); println!("cargo:rustc-link-lib=keystone"); + + let target = std::env::var("TARGET").unwrap(); + if target.contains("apple") { + println!("cargo:rustc-link-lib=dylib=c++"); + } else if target.contains("linux") { + println!("cargo:rustc-link-lib=dylib=stdc++"); + } else if target.contains("windows") { + println!("cargo:rustc-link-lib=dylib=shell32"); + } } fn main() { @@ -44,24 +47,7 @@ fn main() { #[cfg(feature = "use_system_keystone")] pkg_config::find_library("keystone").expect("Could not find system keystone"); } else { + #[cfg(feature = "build_keystone_cmake")] build_with_cmake(); } } - -fn run(cmd: &mut Command) { - println!("run: {:?}", cmd); - let status = match cmd.status() { - Ok(s) => s, - Err(ref e) => fail(&format!("failed to execute command: {}", e)), - }; - if !status.success() { - fail(&format!( - "command did not execute successfully, got: {}", - status - )); - } -} - -fn fail(s: &str) -> ! { - panic!("\n{}\n\nbuild script failed, must exit now", s); -} diff --git a/bindings/rust/keystone-sys/src/lib.rs b/bindings/rust/keystone-sys/src/lib.rs index c063c48a..fa8337fc 100644 --- a/bindings/rust/keystone-sys/src/lib.rs +++ b/bindings/rust/keystone-sys/src/lib.rs @@ -9,17 +9,16 @@ extern crate libc; pub mod keystone_const; -use std::fmt; +use keystone_const::{Arch, Error, Mode, OptionType, OptionValue}; use std::ffi::CStr; +use std::fmt; use std::os::raw::c_char; -use keystone_const::{Arch, Error, Mode, OptionType, OptionValue}; #[allow(non_camel_case_types)] pub type ks_handle = libc::size_t; -#[link(name = "keystone")] extern "C" { - pub fn ks_version(major: *const u32, minor: *const u32) -> u32; + pub fn ks_version(major: *mut u32, minor: *mut u32) -> u32; pub fn ks_arch_supported(arch: Arch) -> bool; pub fn ks_open(arch: Arch, mode: Mode, engine: *mut ks_handle) -> Error; pub fn ks_asm( @@ -38,8 +37,8 @@ extern "C" { } impl Error { - pub fn msg(&self) -> String { - error_msg(*self) + pub fn msg(self) -> String { + error_msg(self) } } diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 5bcd5bfd..29528808 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -1,6 +1,6 @@ -//! Keystone Assembler Engine (www.keystone-engine.org) */ -//! By Nguyen Anh Quynh , 2016 */ -//! Rust bindings by Remco Verhoef , 2016 */ +//! Keystone Assembler Engine (www.keystone-engine.org) \ +//! By Nguyen Anh Quynh , 2016 \ +//! Rust bindings by Remco Verhoef , 2016 //! //! ```rust //! extern crate keystone; @@ -16,12 +16,10 @@ //! } //! ``` -#![doc(html_root_url = "https://keystone/doc/here/v1")] - extern crate keystone_sys as ffi; extern crate libc; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use std::fmt; pub use ffi::keystone_const::*; @@ -66,7 +64,7 @@ pub fn arch_supported(arch: Arch) -> bool { pub fn error_msg(error: Error) -> String { unsafe { - CStr::from_ptr(ffi::ks_strerror(error.bits())) + CStr::from_ptr(ffi::ks_strerror(error)) .to_string_lossy() .into_owned() } diff --git a/include/keystone/keystone.h b/include/keystone/keystone.h index 87305c97..f131b230 100644 --- a/include/keystone/keystone.h +++ b/include/keystone/keystone.h @@ -68,6 +68,9 @@ typedef enum ks_mode { KS_MODE_ARM = 1 << 0, // ARM mode KS_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2) KS_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM + KS_MODE_V4 = 1 << 7, + KS_MODE_XSCALE = 1 << 8, + KS_MODE_V5 = 1 << 9, // mips KS_MODE_MICRO = 1 << 4, // MicroMips mode KS_MODE_MIPS3 = 1 << 5, // Mips III ISA diff --git a/kstool/kstool.cpp b/kstool/kstool.cpp index 7bf57a63..cf083220 100644 --- a/kstool/kstool.cpp +++ b/kstool/kstool.cpp @@ -36,6 +36,12 @@ static void usage(char *prog) if (ks_arch_supported(KS_ARCH_ARM)) { printf(" arm: ARM - little endian\n"); printf(" armbe: ARM - big endian\n"); + printf(" armv4t: ARM V4T - little endian\n"); + printf(" armv4tbe: ARM V4T - big endian\n"); + printf(" armv5: ARM V5 - little endian\n"); + printf(" armv5be: ARM V5 - big endian\n"); + printf(" xscale: XSCALE - little endian\n"); + printf(" xscale: XSCALE - big endian\n"); printf(" thumb: Thumb - little endian\n"); printf(" thumbbe: Thumb - big endian\n"); printf(" armv8: ARM V8 - little endian\n"); @@ -208,6 +214,31 @@ int main(int argc, char **argv) err = ks_open(KS_ARCH_ARM, KS_MODE_ARM+KS_MODE_BIG_ENDIAN, &ks); } + if (!strcmp(mode, "xscale")) { + err = ks_open(KS_ARCH_ARM, KS_MODE_XSCALE+KS_MODE_LITTLE_ENDIAN+KS_MODE_ARM, &ks); + } + + if (!strcmp(mode, "xscalebe")) { + err = ks_open(KS_ARCH_ARM, KS_MODE_XSCALE+KS_MODE_BIG_ENDIAN+KS_MODE_ARM, &ks); + } + + if (!strcmp(mode, "armv4t")) { + err = ks_open(KS_ARCH_ARM, KS_MODE_V4+KS_MODE_LITTLE_ENDIAN+KS_MODE_ARM, &ks); + } + + if (!strcmp(mode, "armv4tbe")) { + err = ks_open(KS_ARCH_ARM, KS_MODE_V4+KS_MODE_BIG_ENDIAN+KS_MODE_ARM, &ks); + } + + if (!strcmp(mode, "armv5")) { + err = ks_open(KS_ARCH_ARM, KS_MODE_V5+KS_MODE_LITTLE_ENDIAN+KS_MODE_ARM, &ks); + } + + if (!strcmp(mode, "armv5be")) { + err = ks_open(KS_ARCH_ARM, KS_MODE_V5+KS_MODE_BIG_ENDIAN+KS_MODE_ARM, &ks); + } + + if (!strcmp(mode, "thumb")) { err = ks_open(KS_ARCH_ARM, KS_MODE_THUMB+KS_MODE_LITTLE_ENDIAN, &ks); } diff --git a/kstool/test-all.sh b/kstool/test-all.sh index efbead76..911eff8b 100755 --- a/kstool/test-all.sh +++ b/kstool/test-all.sh @@ -30,6 +30,37 @@ kstool armbe "sub r1, r2, r5" #encoding: [0x05,0x10,0x42,0xe0] echo +echo "::XScale" +kstool xscale "nop" +#encoding: [0x00, 0x00, 0xa0, 0xe1] +echo + +echo "::XScale BE" +kstool xscalebe "nop" +#encoding: [0xe1, 0xa0, 0x00, 0x00] +echo + +echo "::ARMv4t" +kstool armv4t "nop" +#encoding: [0x00, 0x00, 0xa0, 0xe1] +echo + +echo "::ARMv4t BE" +kstool armv4tbe "nop" +#encoding: [0xe1, 0xa0, 0x00, 0x00] +echo + +echo "::ARMv5" +kstool armv5 "nop" +#encoding: [0x00, 0x00, 0xa0, 0xe1] +echo + +echo "::ARMv5 BE" +kstool armv5be "nop" +#encoding: [0xe1, 0xa0, 0x00, 0x00] +echo + + echo "::Thumb LE" kstool thumb "movs r4, #0xf0" #encoding: [0xf0,0x24] diff --git a/llvm/keystone/ks.cpp b/llvm/keystone/ks.cpp index 63de0d89..7e417178 100644 --- a/llvm/keystone/ks.cpp +++ b/llvm/keystone/ks.cpp @@ -293,7 +293,16 @@ ks_err ks_open(ks_arch arch, int mode, ks_engine **result) case KS_MODE_BIG_ENDIAN | KS_MODE_THUMB: TripleName = "thumbebv7"; break; - + case KS_MODE_BIG_ENDIAN | KS_MODE_V4 | KS_MODE_ARM: + TripleName = "armv4teb"; + break; + case KS_MODE_BIG_ENDIAN | KS_MODE_XSCALE | KS_MODE_ARM: + TripleName = "xscaleeb"; + break; + case KS_MODE_BIG_ENDIAN | KS_MODE_V5 | KS_MODE_ARM: + TripleName = "armv5eb"; + break; + // little-endian case KS_MODE_LITTLE_ENDIAN | KS_MODE_V8 | KS_MODE_ARM: TripleName = "armv8"; @@ -307,6 +316,15 @@ ks_err ks_open(ks_arch arch, int mode, ks_engine **result) case KS_MODE_LITTLE_ENDIAN | KS_MODE_THUMB: TripleName = "thumbv7"; break; + case KS_MODE_LITTLE_ENDIAN | KS_MODE_V4 | KS_MODE_ARM: + TripleName = "armv4t"; + break; + case KS_MODE_LITTLE_ENDIAN | KS_MODE_XSCALE | KS_MODE_ARM: + TripleName = "xscale"; + break; + case KS_MODE_LITTLE_ENDIAN | KS_MODE_V5 | KS_MODE_ARM: + TripleName = "armv5"; + break; } InitKs(arch, ks, TripleName); @@ -540,6 +558,7 @@ ks_err ks_close(ks_engine *ks) KEYSTONE_EXPORT ks_err ks_option(ks_engine *ks, ks_opt_type type, size_t value) { + ks->MAI->setRadix(16); switch(type) { case KS_OPT_SYNTAX: if (ks->arch != KS_ARCH_X86) diff --git a/llvm/keystone/ks_priv.h b/llvm/keystone/ks_priv.h index 1a2b3c1e..4aa2ca7b 100644 --- a/llvm/keystone/ks_priv.h +++ b/llvm/keystone/ks_priv.h @@ -20,7 +20,7 @@ // These are masks of supported modes for each cpu/arch. // They should be updated when changes are made to the ks_mode enum typedef. -#define KS_MODE_ARM_MASK (KS_MODE_ARM|KS_MODE_THUMB|KS_MODE_LITTLE_ENDIAN|KS_MODE_BIG_ENDIAN|KS_MODE_V8) +#define KS_MODE_ARM_MASK (KS_MODE_ARM|KS_MODE_THUMB|KS_MODE_LITTLE_ENDIAN|KS_MODE_BIG_ENDIAN|KS_MODE_V8|KS_MODE_V4|KS_MODE_XSCALE|KS_MODE_V5) #define KS_MODE_MIPS_MASK (KS_MODE_MIPS32|KS_MODE_MIPS64|KS_MODE_LITTLE_ENDIAN|KS_MODE_BIG_ENDIAN) #define KS_MODE_X86_MASK (KS_MODE_16|KS_MODE_32|KS_MODE_64|KS_MODE_LITTLE_ENDIAN) #define KS_MODE_PPC_MASK (KS_MODE_PPC32|KS_MODE_PPC64|KS_MODE_LITTLE_ENDIAN|KS_MODE_BIG_ENDIAN) diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 3446db06..5f4a3115 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -581,6 +581,10 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, AsmParser::~AsmParser() { assert((HadError || ActiveMacros.empty()) && "Unexpected active macro instantiation!"); + + // Restore the saved diagnostics handler and context for use during + // finalization + SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext); } void AsmParser::printMacroInstantiations() { diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index e3b18853..0dc20a32 100644 --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -503,25 +503,13 @@ struct PPCOperand : public MCParsedAsmOperand { } bool isTLSReg() const { return Kind == TLSRegister; } bool isDirectBr() const { - if (Kind == Expression) - return true; - if (Kind != Immediate) - return false; - // Operand must be 64-bit aligned, signed 27-bit immediate. - if ((getImm() & 3) != 0) - return false; - if (isInt<26>(getImm())) - return true; - if (!IsPPC64) { - // In 32-bit mode, large 32-bit quantities wrap around. - if (isUInt<32>(getImm()) && isInt<26>(static_cast(getImm()))) - return true; - } - return false; + return (Kind == Expression) + ||((Kind == Immediate) && ((getImm() & 3) == 0)); + } + bool isCondBr() const { + return (Kind == Expression) + ||((Kind == Immediate) && ((getImm() & 3) == 0)); } - bool isCondBr() const { return Kind == Expression || - (Kind == Immediate && isInt<16>(getImm()) && - (getImm() & 3) == 0); } bool isRegNumber() const { return Kind == Immediate && isUInt<5>(getImm()); } bool isVSRegNumber() const { return Kind == Immediate && isUInt<6>(getImm()); } bool isCCRegNumber() const { return (Kind == Expression @@ -828,6 +816,7 @@ addNegOperand(MCInst &Inst, MCOperand &Op, MCContext &Ctx) { void PPCAsmParser::ProcessInstruction(MCInst &Inst, const OperandVector &Operands) { int Opcode = Inst.getOpcode(); + uint64_t address = Inst.getAddress(); switch (Opcode) { case PPC::DCBTx: case PPC::DCBTT: @@ -1193,6 +1182,8 @@ void PPCAsmParser::ProcessInstruction(MCInst &Inst, break; } } + // if original instruction was overwritten, need to preserve its address + Inst.setAddress(address); } bool PPCAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, diff --git a/samples/sample.c b/samples/sample.c index ea82e010..48e1c79f 100644 --- a/samples/sample.c +++ b/samples/sample.c @@ -124,7 +124,13 @@ int main(int argc, char **argv) test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN, "sub r1, r2, r5", 0); test_ks(KS_ARCH_ARM, KS_MODE_THUMB, "movs r4, #0xf0", 0); test_ks(KS_ARCH_ARM, KS_MODE_THUMB + KS_MODE_BIG_ENDIAN, "movs r4, #0xf0", 0); - + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_V4, "nop", 0); + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_V4, "nop", 0); + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_XSCALE, "nop", 0); + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_XSCALE, "nop", 0); + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_V5, "nop", 0); + test_ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_V5, "nop", 0); + // ARM64 test_ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN, "ldr w1, [sp, #0x8]", 0); diff --git a/suite/regress/ppc_address_consistency.py b/suite/regress/ppc_address_consistency.py new file mode 100644 index 00000000..a58a6d0c --- /dev/null +++ b/suite/regress/ppc_address_consistency.py @@ -0,0 +1,63 @@ +from keystone import * +import regress + +# Github issue #427 +# Author: Edward Larson + +class TestAddressConsistency(regress.RegressTest): + def kstest_address_consistency(self, preceding_assembly, start_address=0x1000, branch_address=0x1004): + """ + Check that a relative branch to itself at branch_address emits the same machine code, independent of the + inst_Assembly comes before it. + :param preceding_assembly: Instruction(s) to be assembled before the branch instruction + :param start_address: VM address of the beginning of preceding_assembly + :param branch_address: VM address of the branch instruction + :return: + """ + ks = Ks(KS_ARCH_PPC, KS_MODE_32 | KS_MODE_BIG_ENDIAN) + + branch_assembly = 'b ' + hex(branch_address) + expected_branch_encoding, _ = ks.asm(branch_assembly, branch_address) + + code = preceding_assembly + "; " + branch_assembly + + encoding, count = ks.asm(code, start_address) + emitted_branch_encoding = encoding[-4:] + + self.assertEqual(emitted_branch_encoding, expected_branch_encoding) + + def runTest(self): + # un-aliased instructions + self.kstest_address_consistency("nop") + self.kstest_address_consistency("add 0, 0, 0") + + # aliased instructions + self.kstest_address_consistency("dcbtt 0, 0") + self.kstest_address_consistency("dcbtct 0, 0, 0") + self.kstest_address_consistency("dcbtstct 0, 0, 0") + self.kstest_address_consistency("la 1, 0, 1") + self.kstest_address_consistency("subi 0, 0, 0") + self.kstest_address_consistency("subis 0, 0, 0") + self.kstest_address_consistency("subic 0, 0, 0") + self.kstest_address_consistency("subic. 0, 0, 0") + self.kstest_address_consistency("extlwi 0, 0, 0, 0") + self.kstest_address_consistency("extrwi 0, 0, 0, 0") + self.kstest_address_consistency("inslwi 0, 0, 0, 0") + self.kstest_address_consistency("insrwi 0, 0, 0, 0") + self.kstest_address_consistency("rotrwi 0, 0, 0") + self.kstest_address_consistency("slwi 0, 0, 0") + self.kstest_address_consistency("srwi 0, 0, 0") + self.kstest_address_consistency("clrrwi 0, 0, 0") + self.kstest_address_consistency("clrlslwi 0, 0, 0, 0") + self.kstest_address_consistency("extldi 0, 0, 0, 0") + self.kstest_address_consistency("extrdi 0, 0, 0, 0") + self.kstest_address_consistency("insrdi 0, 0, 0, 0") + self.kstest_address_consistency("rotrdi 0, 0, 0") + self.kstest_address_consistency("sldi 0, 0, 0") + self.kstest_address_consistency("srdi 0, 0, 0") + self.kstest_address_consistency("clrrdi 0, 0, 0") + self.kstest_address_consistency("clrlsldi 0, 0, 0, 0") + self.kstest_address_consistency("rlwinm 0, 0, 0, 1") + self.kstest_address_consistency("rlwimi 0, 0, 0, 1") + self.kstest_address_consistency("rlwnm 0, 0, 0, 1") + self.kstest_address_consistency("mftb 0, 0") diff --git a/suite/regress/ppc_branch_addressing.py b/suite/regress/ppc_branch_addressing.py new file mode 100644 index 00000000..84cebcbb --- /dev/null +++ b/suite/regress/ppc_branch_addressing.py @@ -0,0 +1,43 @@ +from keystone import * +import regress + +# Github issue: #423 +# Author: Edward Larson + +class TestBranchRelativeAddressing(regress.RegressTest): + def kstest(self, arch, mode, code, expect, syntax = 0, address = 0): + ks = Ks(arch, mode) + if syntax != 0: + ks.syntax = syntax + encoding, count = ks.asm(code, address) + self.assertEqual(expect, encoding) + + def runTest(self): + # 0x1fffffc is largest positive branch offset in PPC, 0x2000000 is largest negative branch offset + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"b 0x1fffffc", [0x49, 0xff, 0xff, 0xfc], address=0x0) + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"b 0x2000000", [0x49, 0xff, 0xff, 0xfc], address=0x4) + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"b 0x0", [0x4a, 0x00, 0x00, 0x00], address=0x2000000) + # beyond max positive range, branch will wrap around to negative + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"b 0x2000000", [0x4a, 0, 0, 0], address=0x0) + # beyond max negative range, branch will wrap ardound to positive + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"b 0x0", [0x49, 0xff, 0xff, 0xfc], address=0x2000004) + + +class TestBranchAbsoluteAddressing(regress.RegressTest): + def kstest(self, arch, mode, code, expect, syntax = 0, address = 0): + ks = Ks(arch, mode) + if syntax != 0: + ks.syntax = syntax + encoding, count = ks.asm(code, address) + self.assertEqual(expect, encoding) + + def runTest(self): + # 0x1fffffc is largest absolute offset in PPC + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"ba 0x1fffffc", [0x49, 0xff, 0xff, 0xfe], address=0x0) + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"ba 0x1fffffc", [0x49, 0xff, 0xff, 0xfe], address=0x4) + # beyond max positive range, branch will wrap around to negative + self.kstest(KS_ARCH_PPC, KS_MODE_PPC32 | KS_MODE_BIG_ENDIAN, b"ba 0x2000000", [0x4a, 0, 0, 2], address=0x0) + + +if __name__ == '__main__': + regress.main() \ No newline at end of file diff --git a/suite/regress/test_all_archs.py b/suite/regress/test_all_archs.py index 916511bd..6daee669 100755 --- a/suite/regress/test_all_archs.py +++ b/suite/regress/test_all_archs.py @@ -36,7 +36,13 @@ def runTest(self): self.kstest(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN, b"sub r1, r2, r5", [ 0xe0, 0x42, 0x10, 0x05 ]) self.kstest(KS_ARCH_ARM, KS_MODE_THUMB, b"movs r4, #0xf0", [ 0xf0, 0x24 ]) self.kstest(KS_ARCH_ARM, KS_MODE_THUMB + KS_MODE_BIG_ENDIAN, b"movs r4, #0xf0", [ 0x24, 0xf0 ]) - + self.kstest(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_XSCALE, b"nop", [ 0x00, 0x00, 0xa0, 0xe1 ]) + self.kstest(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_XSCALE, b"nop", [ 0xe1, 0xa0, 0x00, 0x00 ]) + self.kstest(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_V4, b"nop", [ 0x00, 0x00, 0xa0, 0xe1 ]) + self.kstest(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_V4, b"nop", [ 0xe1, 0xa0, 0x00, 0x00 ]) + self.kstest(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_V5, b"nop", [ 0x00, 0x00, 0xa0, 0xe1 ]) + self.kstest(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN + KS_MODE_V5, b"nop", [ 0xe1, 0xa0, 0x00, 0x00 ]) + # ARM64 self.kstest(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN, b"ldr w1, [sp, #0x8]", [ 0xe1, 0x0b, 0x40, 0xb9 ]) diff --git a/suite/test-all.sh b/suite/test-all.sh index efbead76..d1b3b2eb 100755 --- a/suite/test-all.sh +++ b/suite/test-all.sh @@ -30,6 +30,36 @@ kstool armbe "sub r1, r2, r5" #encoding: [0x05,0x10,0x42,0xe0] echo +echo "::XScale" +kstool xscale "nop" +#encoding: [0x00, 0x00, 0xa0, 0xe1] +echo + +echo "::XScale BE" +kstool xscalebe "nop" +#encoding: [0xe1, 0xa0, 0x00, 0x00] +echo + +echo "::ARMv4t" +kstool armv4t "nop" +#encoding: [0x00, 0x00, 0xa0, 0xe1] +echo + +echo "::ARMv4t BE" +kstool armv4tbe "nop" +#encoding: [0xe1, 0xa0, 0x00, 0x00] +echo + +echo "::ARMv5" +kstool armv5 "nop" +#encoding: [0x00, 0x00, 0xa0, 0xe1] +echo + +echo "::ARMv5 BE" +kstool armv5be "nop" +#encoding: [0xe1, 0xa0, 0x00, 0x00] +echo + echo "::Thumb LE" kstool thumb "movs r4, #0xf0" #encoding: [0xf0,0x24] diff --git a/suite/test_diag_printer.py b/suite/test_diag_printer.py new file mode 100755 index 00000000..7ce4443f --- /dev/null +++ b/suite/test_diag_printer.py @@ -0,0 +1,22 @@ +import binascii + +from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM + +ks = Ks(KS_ARCH_ARM, KS_MODE_ARM) + +assembly_text = \ + """ + sub sp, sp, #8 + push {sp, lr} + bl #0xc6ab8 + ldr lr, [sp, #4] + add sp, sp, #8 + pop {r2, r3} + bx lr + """ + +for i in range(100): + output = ks.asm(assembly_text, 0x902c4, as_bytes=True) + # print("{}: {}: {}".format(i, assembly_text, output)) + output_2 = ks.asm("b #0", 0x4, as_bytes=True) + # print("{}: {}: {}".format(i, "b #0", output_2)) diff --git a/suite/test_diag_printer.sh b/suite/test_diag_printer.sh new file mode 100755 index 00000000..c916d49f --- /dev/null +++ b/suite/test_diag_printer.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +for i in $(seq 1 100) +do + python test_diag_printer.py + + if [ $? -ne 0 ] + then + echo "Diagnostic Handler test failed" + exit + fi +done +echo "Diagnostic Handler test pass"