1 // SPDX-License-Identifier: (Apache-2.0 OR MIT) 2 // Copyright 2017 Jan-Erik Rediger <badboy@archlinux.us> 3 // 4 // Adopted from tests in `tests/assembler.rs` 5 6 extern crate rbpf; 7 mod common; 8 9 use rbpf::{assembler::assemble, disassembler::to_insn_vec}; 10 11 // Using a macro to keep actual line numbers in failure output 12 macro_rules! disasm { 13 ($src:expr) => {{ 14 let src = $src; 15 let asm = assemble(src).expect("Can't assemble from string"); 16 let insn = to_insn_vec(&asm); 17 let reasm = insn 18 .into_iter() 19 .map(|ins| ins.desc) 20 .collect::<Vec<_>>() 21 .join("\n"); 22 23 assert_eq!(src, reasm); 24 }}; 25 } 26 27 #[test] 28 fn test_empty() { 29 disasm!(""); 30 } 31 32 // Example for InstructionType::NoOperand. 33 #[test] 34 fn test_exit() { 35 disasm!("exit"); 36 } 37 38 // Example for InstructionType::AluBinary. 39 #[test] 40 fn test_add64() { 41 disasm!("add64 r1, r3"); 42 disasm!("add64 r1, 0x5"); 43 } 44 45 // Example for InstructionType::AluUnary. 46 #[test] 47 fn test_neg64() { 48 disasm!("neg64 r1"); 49 } 50 51 // Example for InstructionType::LoadReg. 52 #[test] 53 fn test_ldxw() { 54 disasm!("ldxw r1, [r2+0x5]"); 55 } 56 57 // Example for InstructionType::StoreImm. 58 #[test] 59 fn test_stw() { 60 disasm!("stw [r2+0x5], 0x7"); 61 } 62 63 // Example for InstructionType::StoreReg. 64 #[test] 65 fn test_stxw() { 66 disasm!("stxw [r2+0x5], r8"); 67 } 68 69 // Example for InstructionType::JumpUnconditional. 70 #[test] 71 fn test_ja() { 72 disasm!("ja +0x8"); 73 } 74 75 // Example for InstructionType::JumpConditional. 76 #[test] 77 fn test_jeq() { 78 disasm!("jeq r1, 0x4, +0x8"); 79 disasm!("jeq r1, r3, +0x8"); 80 } 81 82 // Example for InstructionType::Call. 83 #[test] 84 fn test_call() { 85 disasm!("call 0x3"); 86 } 87 88 // Example for InstructionType::Endian. 89 #[test] 90 fn test_be32() { 91 disasm!("be32 r1"); 92 } 93 94 // Example for InstructionType::LoadImm. 95 #[test] 96 fn test_lddw() { 97 disasm!("lddw r1, 0x1234abcd5678eeff"); 98 disasm!("lddw r1, 0xff11ee22dd33cc44"); 99 } 100 101 // Example for InstructionType::LoadAbs. 102 #[test] 103 fn test_ldabsw() { 104 disasm!("ldabsw 0x1"); 105 } 106 107 // Example for InstructionType::LoadInd. 108 #[test] 109 fn test_ldindw() { 110 disasm!("ldindw r1, 0x2"); 111 } 112 113 // Example for InstructionType::LoadReg. 114 #[test] 115 fn test_ldxdw() { 116 disasm!("ldxdw r1, [r2+0x3]"); 117 } 118 119 // Example for InstructionType::StoreImm. 120 #[test] 121 fn test_sth() { 122 disasm!("sth [r1+0x2], 0x3"); 123 } 124 125 // Example for InstructionType::StoreReg. 126 #[test] 127 fn test_stxh() { 128 disasm!("stxh [r1+0x2], r3"); 129 } 130 131 // Test all supported AluBinary mnemonics. 132 #[test] 133 fn test_alu_binary() { 134 disasm!( 135 "add64 r1, r2 136 sub64 r1, r2 137 mul64 r1, r2 138 div64 r1, r2 139 or64 r1, r2 140 and64 r1, r2 141 lsh64 r1, r2 142 rsh64 r1, r2 143 mod64 r1, r2 144 xor64 r1, r2 145 mov64 r1, r2 146 arsh64 r1, r2" 147 ); 148 149 disasm!( 150 "add64 r1, 0x2 151 sub64 r1, 0x2 152 mul64 r1, 0x2 153 div64 r1, 0x2 154 or64 r1, 0x2 155 and64 r1, 0x2 156 lsh64 r1, 0x2 157 rsh64 r1, 0x2 158 mod64 r1, 0x2 159 xor64 r1, 0x2 160 mov64 r1, 0x2 161 arsh64 r1, 0x2" 162 ); 163 164 disasm!( 165 "add32 r1, r2 166 sub32 r1, r2 167 mul32 r1, r2 168 div32 r1, r2 169 or32 r1, r2 170 and32 r1, r2 171 lsh32 r1, r2 172 rsh32 r1, r2 173 mod32 r1, r2 174 xor32 r1, r2 175 mov32 r1, r2 176 arsh32 r1, r2" 177 ); 178 179 disasm!( 180 "add32 r1, 0x2 181 sub32 r1, 0x2 182 mul32 r1, 0x2 183 div32 r1, 0x2 184 or32 r1, 0x2 185 and32 r1, 0x2 186 lsh32 r1, 0x2 187 rsh32 r1, 0x2 188 mod32 r1, 0x2 189 xor32 r1, 0x2 190 mov32 r1, 0x2 191 arsh32 r1, 0x2" 192 ); 193 } 194 195 // Test all supported AluUnary mnemonics. 196 #[test] 197 fn test_alu_unary() { 198 disasm!( 199 "neg64 r1 200 neg32 r1" 201 ); 202 } 203 204 // Test all supported LoadAbs mnemonics. 205 #[test] 206 fn test_load_abs() { 207 disasm!( 208 "ldabsw 0x1 209 ldabsh 0x1 210 ldabsb 0x1 211 ldabsdw 0x1" 212 ); 213 } 214 215 // Test all supported LoadInd mnemonics. 216 #[test] 217 fn test_load_ind() { 218 disasm!( 219 "ldindw r1, 0x2 220 ldindh r1, 0x2 221 ldindb r1, 0x2 222 ldinddw r1, 0x2" 223 ); 224 } 225 226 // Test all supported LoadReg mnemonics. 227 #[test] 228 fn test_load_reg() { 229 disasm!( 230 r"ldxw r1, [r2+0x3] 231 ldxh r1, [r2+0x3] 232 ldxb r1, [r2+0x3] 233 ldxdw r1, [r2+0x3]" 234 ); 235 } 236 237 // Test all supported StoreImm mnemonics. 238 #[test] 239 fn test_store_imm() { 240 disasm!( 241 "stw [r1+0x2], 0x3 242 sth [r1+0x2], 0x3 243 stb [r1+0x2], 0x3 244 stdw [r1+0x2], 0x3" 245 ); 246 } 247 248 // Test all supported StoreReg mnemonics. 249 #[test] 250 fn test_store_reg() { 251 disasm!( 252 "stxw [r1+0x2], r3 253 stxh [r1+0x2], r3 254 stxb [r1+0x2], r3 255 stxdw [r1+0x2], r3" 256 ); 257 } 258 259 // Test all supported JumpConditional mnemonics. 260 #[test] 261 fn test_jump_conditional() { 262 disasm!( 263 "jeq r1, r2, +0x3 264 jgt r1, r2, +0x3 265 jge r1, r2, +0x3 266 jlt r1, r2, +0x3 267 jle r1, r2, +0x3 268 jset r1, r2, +0x3 269 jne r1, r2, +0x3 270 jsgt r1, r2, +0x3 271 jsge r1, r2, -0x3 272 jslt r1, r2, +0x3 273 jsle r1, r2, -0x3" 274 ); 275 276 disasm!( 277 "jeq r1, 0x2, +0x3 278 jgt r1, 0x2, +0x3 279 jge r1, 0x2, +0x3 280 jlt r1, 0x2, +0x3 281 jle r1, 0x2, +0x3 282 jset r1, 0x2, +0x3 283 jne r1, 0x2, +0x3 284 jsgt r1, 0x2, +0x3 285 jsge r1, 0x2, -0x3 286 jslt r1, 0x2, +0x3 287 jsle r1, 0x2, -0x3" 288 ); 289 290 disasm!( 291 "jeq32 r1, r2, +0x3 292 jgt32 r1, r2, +0x3 293 jge32 r1, r2, +0x3 294 jlt32 r1, r2, +0x3 295 jle32 r1, r2, +0x3 296 jset32 r1, r2, +0x3 297 jne32 r1, r2, +0x3 298 jsgt32 r1, r2, +0x3 299 jsge32 r1, r2, -0x3 300 jslt32 r1, r2, +0x3 301 jsle32 r1, r2, -0x3" 302 ); 303 304 disasm!( 305 "jeq32 r1, 0x2, +0x3 306 jgt32 r1, 0x2, +0x3 307 jge32 r1, 0x2, +0x3 308 jlt32 r1, 0x2, +0x3 309 jle32 r1, 0x2, +0x3 310 jset32 r1, 0x2, +0x3 311 jne32 r1, 0x2, +0x3 312 jsgt32 r1, 0x2, +0x3 313 jsge32 r1, 0x2, -0x3 314 jslt32 r1, 0x2, +0x3 315 jsle32 r1, 0x2, -0x3" 316 ); 317 } 318 319 // Test all supported Endian mnemonics. 320 #[test] 321 fn test_endian() { 322 disasm!( 323 "be16 r1 324 be32 r1 325 be64 r1 326 le16 r1 327 le32 r1 328 le64 r1" 329 ); 330 } 331 332 #[test] 333 fn test_large_immediate() { 334 disasm!("add64 r1, 0x7fffffff"); 335 disasm!("add64 r1, 0x7fffffff"); 336 } 337 338 // Non-regression tests for overflow when trying to negate offset 0x8000i16. 339 #[test] 340 fn test_offset_overflow() { 341 let insns = [ 342 0x62, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stw 343 0x6a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // sth 344 0x72, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stb 345 0x7a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stdw 346 0x61, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxw 347 0x69, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxh 348 0x71, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxb 349 0x79, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxdw 350 0x15, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq (imm) 351 0x1d, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq (reg) 352 0x16, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq32 (imm) 353 0x1e, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq32 (reg) 354 ]; 355 356 let expected_output = "stw [r1-0x8000], 0x1 357 sth [r1-0x8000], 0x1 358 stb [r1-0x8000], 0x1 359 stdw [r1-0x8000], 0x1 360 ldxw r1, [r0-0x8000] 361 ldxh r1, [r0-0x8000] 362 ldxb r1, [r0-0x8000] 363 ldxdw r1, [r0-0x8000] 364 jeq r1, 0x2, -0x8000 365 jeq r1, r2, -0x8000 366 jeq32 r1, 0x2, -0x8000 367 jeq32 r1, r2, -0x8000"; 368 369 let prog = to_insn_vec(&insns); 370 let asm = prog 371 .into_iter() 372 .map(|ins| ins.desc) 373 .collect::<Vec<_>>() 374 .join("\n"); 375 376 assert_eq!(asm, expected_output); 377 } 378