/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "disassembler.h" using namespace panda::disasm; #cmakedefine DISASM_BIN_DIR "@DISASM_BIN_DIR@/" TEST(instructions_test, test_language_panda_assembly) { Disassembler d {}; std::stringstream ss {}; d.Disassemble(std::string(DISASM_BIN_DIR) + "empty_record.bc"); d.Serialize(ss); EXPECT_TRUE(ss.str().find(".language PandaAssembly") != std::string::npos); } TEST(instructions_test, test_ins) { Disassembler d {}; std::stringstream ss {}; d.Disassemble(std::string(DISASM_BIN_DIR) + "instructions.bc"); d.Serialize(ss); size_t beg_g = ss.str().find("g() {"); size_t end_g = ss.str().find('}', beg_g); ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {"))); EXPECT_TRUE(body_g.find("\tmov v0, v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tmov.64 v2, v3") != std::string::npos); EXPECT_TRUE(body_g.find("\tmov.obj v4, v5") != std::string::npos); EXPECT_TRUE(body_g.find("\tmovi v0, 0xffffffffffffffff") != std::string::npos); EXPECT_TRUE(body_g.find("\tmovi.64 v0, 0x2") != std::string::npos); EXPECT_TRUE(body_g.find("\tfmovi.64 v0, 0x4008147ae147ae14") != std::string::npos); EXPECT_TRUE(body_g.find("\tlda v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tlda.64 v0") != std::string::npos); EXPECT_TRUE(body_g.find("\tlda.obj v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldai 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldai.64 0x2") != std::string::npos); EXPECT_TRUE(body_g.find("\tfldai.64 0x4008147ae147ae14") != std::string::npos); EXPECT_TRUE(body_g.find("\tlda.str \"kek\"") != std::string::npos); EXPECT_TRUE(body_g.find("\tlda.type A") != std::string::npos); EXPECT_TRUE(body_g.find("\tlda.null") != std::string::npos); EXPECT_TRUE(body_g.find("\tsta v0") != std::string::npos); EXPECT_TRUE(body_g.find("\tsta.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tsta.obj v2") != std::string::npos); EXPECT_TRUE(body_g.find("jump_label_0:\n\tjmp jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjeq v1, jump_label_1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldai 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tjmp jump_label_2") != std::string::npos); EXPECT_TRUE(body_g.find("jump_label_1:\n\tldai 0x0") != std::string::npos); EXPECT_TRUE(body_g.find("jump_label_2:\n\tcmp.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tucmp v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tucmp.64 v3") != std::string::npos); EXPECT_TRUE(body_g.find("\tfcmpl.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tfcmpg.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tjeqz jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjnez jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjltz jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjgtz jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjlez jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjgez jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjeq v2, jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjne v2, jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjlt v2, jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjgt v2, jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjle v2, jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tjge v2, jump_label_0") != std::string::npos); EXPECT_TRUE(body_g.find("\tfadd2.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tfsub2.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tfmul2.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tfdiv2.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tfmod2.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tadd2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tadd2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tsub2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tsub2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmul2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmul2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tand2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tand2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tor2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tor2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\txor2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\txor2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tshl2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tshl2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tshr2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tshr2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tashr2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tashr2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tdiv2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tdiv2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmod2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmod2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tdivu2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tdivu2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmodu2 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmodu2.64 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tadd v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tsub v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmul v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tand v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tor v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\txor v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tshl v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tshr v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tashr v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tdiv v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tmod v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\taddi 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tsubi 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tmuli 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tandi 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tori 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\txori 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tshli 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tshri 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tashri 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tdivi 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tmodi 0x1") != std::string::npos); EXPECT_TRUE(body_g.find("\tneg") != std::string::npos); EXPECT_TRUE(body_g.find("\tneg.64") != std::string::npos); EXPECT_TRUE(body_g.find("\tnot") != std::string::npos); EXPECT_TRUE(body_g.find("\tnot.64") != std::string::npos); EXPECT_TRUE(body_g.find("\ti32tof64") != std::string::npos); EXPECT_TRUE(body_g.find("\tu32tof64") != std::string::npos); EXPECT_TRUE(body_g.find("\ti64tof64") != std::string::npos); EXPECT_TRUE(body_g.find("\tu64tof64") != std::string::npos); EXPECT_TRUE(body_g.find("\tf64toi32") != std::string::npos); EXPECT_TRUE(body_g.find("\tf64toi64") != std::string::npos); EXPECT_TRUE(body_g.find("\tf64tou32") != std::string::npos); EXPECT_TRUE(body_g.find("\tf64tou64") != std::string::npos); EXPECT_TRUE(body_g.find("\ti32toi64") != std::string::npos); EXPECT_TRUE(body_g.find("\ti64toi32") != std::string::npos); EXPECT_TRUE(body_g.find("\tu32toi64") != std::string::npos); EXPECT_TRUE(body_g.find("\tldarr.8 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldarru.8 v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tldarr.16 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldarru.16 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldarr v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldarr.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tfldarr.32 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tfldarr.64 v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tldarr.obj v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tstarr.8 v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tstarr.16 v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tstarr v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tstarr.64 v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tfstarr.32 v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tfstarr.64 v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tstarr.obj v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewobj v6, A") != std::string::npos); EXPECT_TRUE(body_g.find("\tinitobj.short A.init:()") != std::string::npos); EXPECT_TRUE(body_g.find("\tldobj v0, A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tldobj.64 v0, A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tldobj.obj v0, A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tstobj v1, A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tstobj.64 v1, A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tstobj.obj v1, A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tldstatic A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tldstatic.64 A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tldstatic.obj A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tststatic A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tststatic.64 A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tststatic.obj A.kek") != std::string::npos); EXPECT_TRUE(body_g.find("\tcheckcast A") != std::string::npos); EXPECT_TRUE(body_g.find("\tisinstance A") != std::string::npos); } TEST(instructions_test, test_calls) { Disassembler d {}; std::stringstream ss {}; d.Disassemble(std::string(DISASM_BIN_DIR) + "calls.bc"); d.Serialize(ss); size_t beg_g = ss.str().find("g(u1 a0) {"); size_t end_g = ss.str().find('}', beg_g); ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; std::string body_g = ss.str().substr(beg_g + strlen("g(u1 a0) {"), end_g - (beg_g + strlen("g(u1 a0) {"))); EXPECT_TRUE(body_g.find("\tcall.virt.short B.Bhandler_unspec:(B), v4") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.virt.short B.Bhandler_short:(B,u1), v4, v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.virt B.Bhandler_short2:(B,u1[],i64), v4, v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.virt B.Bhandler_long:(B,i8,i16,i32), v4, v0, v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.virt.range B.Bhandler_range:(B,i8,i16,i32,i8,i16,i32), v4") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.short handler_unspec:()") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.short handler_short:(u1), v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.short handler_short2:(u1,i64), v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall handler_long:(i8,i16,i32), v0, v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall handler_long2:(i8,i16,i32,f64), v0, v1, v2, v3") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.range handler_range:(i8,i16,i32,i8,i16,i32), v0") != std::string::npos); EXPECT_TRUE(body_g.find("\tinitobj.short B.Bhandler_unspec:(B)") != std::string::npos); EXPECT_TRUE(body_g.find("\tinitobj.short B.Bhandler_short:(B,u1), v1") != std::string::npos); EXPECT_TRUE(body_g.find("\tinitobj.short B.Bhandler_short2:(B,u1[],i64), v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tinitobj B.Bhandler_long:(B,i8,i16,i32), v0, v1, v2") != std::string::npos); EXPECT_TRUE(body_g.find("\tinitobj B.Bhandler_long2:(B,i8,i16,i32,i64), v0, v1, v2, v3") != std::string::npos); EXPECT_TRUE(body_g.find("\tinitobj.range B.Bhandler_range:(B,i8,i16,i32,i8,i16,i32), v0") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.acc.short handler_short:(u1), v0, 0x0") != std::string::npos); EXPECT_TRUE(body_g.find("\tcall.acc.short handler_short2:(u1,i64), a0, 0x1") != std::string::npos); EXPECT_TRUE( ss.str().find(".function u16 long_function(i8 a0, i16 a1, i32 a2, i8 a3, i16 a4, i32 a5, i64 a6, f32 a7)") != std::string::npos); EXPECT_TRUE(body_g.find("\tcalli.dyn.short 0x1, v0") != std::string::npos); } TEST(instructions_test, test_returns) { Disassembler d {}; std::stringstream ss {}; d.Disassemble(std::string(DISASM_BIN_DIR) + "returns.bc"); d.Serialize(ss); EXPECT_TRUE(ss.str().find("\treturn") != std::string::npos); EXPECT_TRUE(ss.str().find("\treturn.64") != std::string::npos); EXPECT_TRUE(ss.str().find("\treturn.obj") != std::string::npos); EXPECT_TRUE(ss.str().find("\treturn.void") != std::string::npos); } TEST(instructions_test, test_newarr) { Disassembler d {}; std::stringstream ss {}; d.Disassemble(std::string(DISASM_BIN_DIR) + "newarrs.bc"); d.Serialize(ss); size_t beg_g = ss.str().find("g(u1 a0) {"); size_t end_g = ss.str().find('}', beg_g); ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {"))); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u1[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i8[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u8[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i16[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u16[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i32[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u32[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, f32[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, f64[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i64[]") != std::string::npos); EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u64[]") != std::string::npos); } TEST(instructions_test, test_debug_info) { Disassembler d; std::stringstream ss; d.Disassemble(std::string(DISASM_BIN_DIR) + "instructions.bc"); d.CollectInfo(); d.Serialize(ss, true, true); size_t beg_g = ss.str().find("g() {"); size_t end_g = ss.str().find('}', beg_g); ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {"))); ASSERT_NE(body_g.find("# LINE_NUMBER_TABLE:"), std::string::npos); ASSERT_NE(body_g.find("#\tline 26: 0\n"), std::string::npos); size_t code_start = body_g.find("# CODE:\n"); ASSERT_NE(code_start, std::string::npos) << "Code section in function g not found"; size_t code_end = body_g.find("\n\n"); // First gap in function body is code section end ASSERT_NE(code_end, std::string::npos) << "Gap after code section in function g not found"; ASSERT_LT(code_start, code_end); std::string instructions = body_g.substr(code_start + strlen("# CODE:\n"), code_end + 1 - (code_start + strlen("# CODE:\n"))); size_t instruction_count = std::count(instructions.begin(), instructions.end(), '\n'); const ProgInfo &prog_info = d.GetProgInfo(); auto g_it = prog_info.methods_info.find("g:()"); ASSERT_NE(g_it, prog_info.methods_info.end()); // In case of pandasm the table should contain entry on each instruction ASSERT_EQ(g_it->second.line_number_table.size(), instruction_count); // There should be no local variables for panda assembler ASSERT_EQ(body_g.find("# LOCAL_VARIABLE_TABLE:"), std::string::npos); } #undef DISASM_BIN_DIR