1/* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <iostream> 17#include <string> 18 19#include <gtest/gtest.h> 20#include "disassembler.h" 21 22using namespace panda::disasm; 23 24#cmakedefine DISASM_BIN_DIR "@DISASM_BIN_DIR@/" 25 26TEST(instructions_test, test_language_panda_assembly) 27{ 28 Disassembler d {}; 29 30 std::stringstream ss {}; 31 d.Disassemble(std::string(DISASM_BIN_DIR) + "empty_record.bc"); 32 d.Serialize(ss); 33 34 EXPECT_TRUE(ss.str().find(".language PandaAssembly") != std::string::npos); 35} 36 37TEST(instructions_test, test_ins) 38{ 39 Disassembler d {}; 40 41 std::stringstream ss {}; 42 d.Disassemble(std::string(DISASM_BIN_DIR) + "instructions.bc"); 43 d.Serialize(ss); 44 45 size_t beg_g = ss.str().find("g() <static> {"); 46 size_t end_g = ss.str().find('}', beg_g); 47 48 ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; 49 50 std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {"))); 51 52 EXPECT_TRUE(body_g.find("\tmov v0, v1") != std::string::npos); 53 EXPECT_TRUE(body_g.find("\tmov.64 v2, v3") != std::string::npos); 54 EXPECT_TRUE(body_g.find("\tmov.obj v4, v5") != std::string::npos); 55 56 EXPECT_TRUE(body_g.find("\tmovi v0, 0xffffffffffffffff") != std::string::npos); 57 EXPECT_TRUE(body_g.find("\tmovi.64 v0, 0x2") != std::string::npos); 58 EXPECT_TRUE(body_g.find("\tfmovi.64 v0, 0x4008147ae147ae14") != std::string::npos); 59 60 EXPECT_TRUE(body_g.find("\tlda v1") != std::string::npos); 61 EXPECT_TRUE(body_g.find("\tlda.64 v0") != std::string::npos); 62 EXPECT_TRUE(body_g.find("\tlda.obj v1") != std::string::npos); 63 64 EXPECT_TRUE(body_g.find("\tldai 0x1") != std::string::npos); 65 EXPECT_TRUE(body_g.find("\tldai.64 0x2") != std::string::npos); 66 EXPECT_TRUE(body_g.find("\tfldai.64 0x4008147ae147ae14") != std::string::npos); 67 EXPECT_TRUE(body_g.find("\tlda.str \"kek\"") != std::string::npos); 68 EXPECT_TRUE(body_g.find("\tlda.type A") != std::string::npos); 69 EXPECT_TRUE(body_g.find("\tlda.null") != std::string::npos); 70 71 EXPECT_TRUE(body_g.find("\tsta v0") != std::string::npos); 72 EXPECT_TRUE(body_g.find("\tsta.64 v1") != std::string::npos); 73 EXPECT_TRUE(body_g.find("\tsta.obj v2") != std::string::npos); 74 75 EXPECT_TRUE(body_g.find("jump_label_0:\n\tjmp jump_label_0") != std::string::npos); 76 EXPECT_TRUE(body_g.find("\tjeq v1, jump_label_1") != std::string::npos); 77 EXPECT_TRUE(body_g.find("\tldai 0x1") != std::string::npos); 78 EXPECT_TRUE(body_g.find("\tjmp jump_label_2") != std::string::npos); 79 EXPECT_TRUE(body_g.find("jump_label_1:\n\tldai 0x0") != std::string::npos); 80 EXPECT_TRUE(body_g.find("jump_label_2:\n\tcmp.64 v1") != std::string::npos); 81 EXPECT_TRUE(body_g.find("\tucmp v2") != std::string::npos); 82 EXPECT_TRUE(body_g.find("\tucmp.64 v3") != std::string::npos); 83 84 EXPECT_TRUE(body_g.find("\tfcmpl.64 v1") != std::string::npos); 85 EXPECT_TRUE(body_g.find("\tfcmpg.64 v1") != std::string::npos); 86 87 EXPECT_TRUE(body_g.find("\tjeqz jump_label_0") != std::string::npos); 88 EXPECT_TRUE(body_g.find("\tjnez jump_label_0") != std::string::npos); 89 EXPECT_TRUE(body_g.find("\tjltz jump_label_0") != std::string::npos); 90 EXPECT_TRUE(body_g.find("\tjgtz jump_label_0") != std::string::npos); 91 EXPECT_TRUE(body_g.find("\tjlez jump_label_0") != std::string::npos); 92 EXPECT_TRUE(body_g.find("\tjgez jump_label_0") != std::string::npos); 93 94 EXPECT_TRUE(body_g.find("\tjeq v2, jump_label_0") != std::string::npos); 95 EXPECT_TRUE(body_g.find("\tjne v2, jump_label_0") != std::string::npos); 96 EXPECT_TRUE(body_g.find("\tjlt v2, jump_label_0") != std::string::npos); 97 EXPECT_TRUE(body_g.find("\tjgt v2, jump_label_0") != std::string::npos); 98 EXPECT_TRUE(body_g.find("\tjle v2, jump_label_0") != std::string::npos); 99 EXPECT_TRUE(body_g.find("\tjge v2, jump_label_0") != std::string::npos); 100 101 EXPECT_TRUE(body_g.find("\tfadd2.64 v1") != std::string::npos); 102 EXPECT_TRUE(body_g.find("\tfsub2.64 v1") != std::string::npos); 103 EXPECT_TRUE(body_g.find("\tfmul2.64 v1") != std::string::npos); 104 EXPECT_TRUE(body_g.find("\tfdiv2.64 v1") != std::string::npos); 105 EXPECT_TRUE(body_g.find("\tfmod2.64 v1") != std::string::npos); 106 107 EXPECT_TRUE(body_g.find("\tadd2 v2") != std::string::npos); 108 EXPECT_TRUE(body_g.find("\tadd2.64 v2") != std::string::npos); 109 EXPECT_TRUE(body_g.find("\tsub2 v2") != std::string::npos); 110 EXPECT_TRUE(body_g.find("\tsub2.64 v2") != std::string::npos); 111 EXPECT_TRUE(body_g.find("\tmul2 v2") != std::string::npos); 112 EXPECT_TRUE(body_g.find("\tmul2.64 v2") != std::string::npos); 113 EXPECT_TRUE(body_g.find("\tand2 v2") != std::string::npos); 114 EXPECT_TRUE(body_g.find("\tand2.64 v2") != std::string::npos); 115 EXPECT_TRUE(body_g.find("\tor2 v2") != std::string::npos); 116 EXPECT_TRUE(body_g.find("\tor2.64 v2") != std::string::npos); 117 EXPECT_TRUE(body_g.find("\txor2 v2") != std::string::npos); 118 EXPECT_TRUE(body_g.find("\txor2.64 v2") != std::string::npos); 119 EXPECT_TRUE(body_g.find("\tshl2 v2") != std::string::npos); 120 EXPECT_TRUE(body_g.find("\tshl2.64 v2") != std::string::npos); 121 EXPECT_TRUE(body_g.find("\tshr2 v2") != std::string::npos); 122 EXPECT_TRUE(body_g.find("\tshr2.64 v2") != std::string::npos); 123 EXPECT_TRUE(body_g.find("\tashr2 v2") != std::string::npos); 124 EXPECT_TRUE(body_g.find("\tashr2.64 v2") != std::string::npos); 125 EXPECT_TRUE(body_g.find("\tdiv2 v2") != std::string::npos); 126 EXPECT_TRUE(body_g.find("\tdiv2.64 v2") != std::string::npos); 127 EXPECT_TRUE(body_g.find("\tmod2 v2") != std::string::npos); 128 EXPECT_TRUE(body_g.find("\tmod2.64 v2") != std::string::npos); 129 EXPECT_TRUE(body_g.find("\tdivu2 v2") != std::string::npos); 130 EXPECT_TRUE(body_g.find("\tdivu2.64 v2") != std::string::npos); 131 EXPECT_TRUE(body_g.find("\tmodu2 v2") != std::string::npos); 132 EXPECT_TRUE(body_g.find("\tmodu2.64 v2") != std::string::npos); 133 134 EXPECT_TRUE(body_g.find("\tadd v1, v2") != std::string::npos); 135 EXPECT_TRUE(body_g.find("\tsub v1, v2") != std::string::npos); 136 EXPECT_TRUE(body_g.find("\tmul v1, v2") != std::string::npos); 137 EXPECT_TRUE(body_g.find("\tand v1, v2") != std::string::npos); 138 EXPECT_TRUE(body_g.find("\tor v1, v2") != std::string::npos); 139 EXPECT_TRUE(body_g.find("\txor v1, v2") != std::string::npos); 140 EXPECT_TRUE(body_g.find("\tshl v1, v2") != std::string::npos); 141 EXPECT_TRUE(body_g.find("\tshr v1, v2") != std::string::npos); 142 EXPECT_TRUE(body_g.find("\tashr v1, v2") != std::string::npos); 143 EXPECT_TRUE(body_g.find("\tdiv v1, v2") != std::string::npos); 144 EXPECT_TRUE(body_g.find("\tmod v1, v2") != std::string::npos); 145 146 EXPECT_TRUE(body_g.find("\taddi 0x1") != std::string::npos); 147 EXPECT_TRUE(body_g.find("\tsubi 0x1") != std::string::npos); 148 EXPECT_TRUE(body_g.find("\tmuli 0x1") != std::string::npos); 149 EXPECT_TRUE(body_g.find("\tandi 0x1") != std::string::npos); 150 EXPECT_TRUE(body_g.find("\tori 0x1") != std::string::npos); 151 EXPECT_TRUE(body_g.find("\txori 0x1") != std::string::npos); 152 EXPECT_TRUE(body_g.find("\tshli 0x1") != std::string::npos); 153 EXPECT_TRUE(body_g.find("\tshri 0x1") != std::string::npos); 154 EXPECT_TRUE(body_g.find("\tashri 0x1") != std::string::npos); 155 EXPECT_TRUE(body_g.find("\tdivi 0x1") != std::string::npos); 156 EXPECT_TRUE(body_g.find("\tmodi 0x1") != std::string::npos); 157 158 EXPECT_TRUE(body_g.find("\tneg") != std::string::npos); 159 EXPECT_TRUE(body_g.find("\tneg.64") != std::string::npos); 160 EXPECT_TRUE(body_g.find("\tnot") != std::string::npos); 161 EXPECT_TRUE(body_g.find("\tnot.64") != std::string::npos); 162 163 EXPECT_TRUE(body_g.find("\ti32tof64") != std::string::npos); 164 EXPECT_TRUE(body_g.find("\tu32tof64") != std::string::npos); 165 EXPECT_TRUE(body_g.find("\ti64tof64") != std::string::npos); 166 EXPECT_TRUE(body_g.find("\tu64tof64") != std::string::npos); 167 EXPECT_TRUE(body_g.find("\tf64toi32") != std::string::npos); 168 EXPECT_TRUE(body_g.find("\tf64toi64") != std::string::npos); 169 EXPECT_TRUE(body_g.find("\tf64tou32") != std::string::npos); 170 EXPECT_TRUE(body_g.find("\tf64tou64") != std::string::npos); 171 EXPECT_TRUE(body_g.find("\ti32toi64") != std::string::npos); 172 EXPECT_TRUE(body_g.find("\ti64toi32") != std::string::npos); 173 EXPECT_TRUE(body_g.find("\tu32toi64") != std::string::npos); 174 175 EXPECT_TRUE(body_g.find("\tldarr.8 v1") != std::string::npos); 176 EXPECT_TRUE(body_g.find("\tldarru.8 v2") != std::string::npos); 177 EXPECT_TRUE(body_g.find("\tldarr.16 v1") != std::string::npos); 178 EXPECT_TRUE(body_g.find("\tldarru.16 v1") != std::string::npos); 179 EXPECT_TRUE(body_g.find("\tldarr v1") != std::string::npos); 180 EXPECT_TRUE(body_g.find("\tldarr.64 v1") != std::string::npos); 181 EXPECT_TRUE(body_g.find("\tfldarr.32 v1") != std::string::npos); 182 EXPECT_TRUE(body_g.find("\tfldarr.64 v1") != std::string::npos); 183 EXPECT_TRUE(body_g.find("\tldarr.obj v1") != std::string::npos); 184 185 EXPECT_TRUE(body_g.find("\tstarr.8 v1, v2") != std::string::npos); 186 EXPECT_TRUE(body_g.find("\tstarr.16 v1, v2") != std::string::npos); 187 EXPECT_TRUE(body_g.find("\tstarr v1, v2") != std::string::npos); 188 EXPECT_TRUE(body_g.find("\tstarr.64 v1, v2") != std::string::npos); 189 EXPECT_TRUE(body_g.find("\tfstarr.32 v1, v2") != std::string::npos); 190 EXPECT_TRUE(body_g.find("\tfstarr.64 v1, v2") != std::string::npos); 191 EXPECT_TRUE(body_g.find("\tstarr.obj v1, v2") != std::string::npos); 192 193 EXPECT_TRUE(body_g.find("\tnewobj v6, A") != std::string::npos); 194 195 EXPECT_TRUE(body_g.find("\tinitobj.short A.init:()") != std::string::npos); 196 197 EXPECT_TRUE(body_g.find("\tldobj v0, A.kek") != std::string::npos); 198 EXPECT_TRUE(body_g.find("\tldobj.64 v0, A.kek") != std::string::npos); 199 EXPECT_TRUE(body_g.find("\tldobj.obj v0, A.kek") != std::string::npos); 200 201 EXPECT_TRUE(body_g.find("\tstobj v1, A.kek") != std::string::npos); 202 EXPECT_TRUE(body_g.find("\tstobj.64 v1, A.kek") != std::string::npos); 203 EXPECT_TRUE(body_g.find("\tstobj.obj v1, A.kek") != std::string::npos); 204 205 EXPECT_TRUE(body_g.find("\tldstatic A.kek") != std::string::npos); 206 EXPECT_TRUE(body_g.find("\tldstatic.64 A.kek") != std::string::npos); 207 EXPECT_TRUE(body_g.find("\tldstatic.obj A.kek") != std::string::npos); 208 209 EXPECT_TRUE(body_g.find("\tststatic A.kek") != std::string::npos); 210 EXPECT_TRUE(body_g.find("\tststatic.64 A.kek") != std::string::npos); 211 EXPECT_TRUE(body_g.find("\tststatic.obj A.kek") != std::string::npos); 212 213 EXPECT_TRUE(body_g.find("\tcheckcast A") != std::string::npos); 214 EXPECT_TRUE(body_g.find("\tisinstance A") != std::string::npos); 215} 216 217TEST(instructions_test, test_calls) 218{ 219 Disassembler d {}; 220 221 std::stringstream ss {}; 222 d.Disassemble(std::string(DISASM_BIN_DIR) + "calls.bc"); 223 d.Serialize(ss); 224 225 size_t beg_g = ss.str().find("g(u1 a0) <static> {"); 226 size_t end_g = ss.str().find('}', beg_g); 227 228 ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; 229 230 std::string body_g = 231 ss.str().substr(beg_g + strlen("g(u1 a0) <static> {"), end_g - (beg_g + strlen("g(u1 a0) <static> {"))); 232 233 EXPECT_TRUE(body_g.find("\tcall.virt.short B.Bhandler_unspec:(B), v4") != std::string::npos); 234 EXPECT_TRUE(body_g.find("\tcall.virt.short B.Bhandler_short:(B,u1), v4, v1") != std::string::npos); 235 EXPECT_TRUE(body_g.find("\tcall.virt B.Bhandler_short2:(B,u1[],i64), v4, v1, v2") != std::string::npos); 236 EXPECT_TRUE(body_g.find("\tcall.virt B.Bhandler_long:(B,i8,i16,i32), v4, v0, v1, v2") != std::string::npos); 237 EXPECT_TRUE(body_g.find("\tcall.virt.range B.Bhandler_range:(B,i8,i16,i32,i8,i16,i32), v4") != std::string::npos); 238 239 EXPECT_TRUE(body_g.find("\tcall.short handler_unspec:()") != std::string::npos); 240 EXPECT_TRUE(body_g.find("\tcall.short handler_short:(u1), v1") != std::string::npos); 241 EXPECT_TRUE(body_g.find("\tcall.short handler_short2:(u1,i64), v1, v2") != std::string::npos); 242 EXPECT_TRUE(body_g.find("\tcall handler_long:(i8,i16,i32), v0, v1, v2") != std::string::npos); 243 EXPECT_TRUE(body_g.find("\tcall handler_long2:(i8,i16,i32,f64), v0, v1, v2, v3") != std::string::npos); 244 EXPECT_TRUE(body_g.find("\tcall.range handler_range:(i8,i16,i32,i8,i16,i32), v0") != std::string::npos); 245 246 EXPECT_TRUE(body_g.find("\tinitobj.short B.Bhandler_unspec:(B)") != std::string::npos); 247 EXPECT_TRUE(body_g.find("\tinitobj.short B.Bhandler_short:(B,u1), v1") != std::string::npos); 248 EXPECT_TRUE(body_g.find("\tinitobj.short B.Bhandler_short2:(B,u1[],i64), v1, v2") != std::string::npos); 249 EXPECT_TRUE(body_g.find("\tinitobj B.Bhandler_long:(B,i8,i16,i32), v0, v1, v2") != std::string::npos); 250 EXPECT_TRUE(body_g.find("\tinitobj B.Bhandler_long2:(B,i8,i16,i32,i64), v0, v1, v2, v3") != std::string::npos); 251 EXPECT_TRUE(body_g.find("\tinitobj.range B.Bhandler_range:(B,i8,i16,i32,i8,i16,i32), v0") != std::string::npos); 252 253 EXPECT_TRUE(body_g.find("\tcall.acc.short handler_short:(u1), v0, 0x0") != std::string::npos); 254 EXPECT_TRUE(body_g.find("\tcall.acc.short handler_short2:(u1,i64), a0, 0x1") != std::string::npos); 255 256 EXPECT_TRUE( 257 ss.str().find(".function u16 long_function(i8 a0, i16 a1, i32 a2, i8 a3, i16 a4, i32 a5, i64 a6, f32 a7)") != 258 std::string::npos); 259 260 EXPECT_TRUE(body_g.find("\tcalli.dyn.short 0x1, v0") != std::string::npos); 261} 262 263TEST(instructions_test, test_returns) 264{ 265 Disassembler d {}; 266 267 std::stringstream ss {}; 268 d.Disassemble(std::string(DISASM_BIN_DIR) + "returns.bc"); 269 d.Serialize(ss); 270 271 EXPECT_TRUE(ss.str().find("\treturn") != std::string::npos); 272 EXPECT_TRUE(ss.str().find("\treturn.64") != std::string::npos); 273 EXPECT_TRUE(ss.str().find("\treturn.obj") != std::string::npos); 274 EXPECT_TRUE(ss.str().find("\treturn.void") != std::string::npos); 275} 276 277TEST(instructions_test, test_newarr) 278{ 279 Disassembler d {}; 280 281 std::stringstream ss {}; 282 d.Disassemble(std::string(DISASM_BIN_DIR) + "newarrs.bc"); 283 d.Serialize(ss); 284 285 size_t beg_g = ss.str().find("g(u1 a0) <static> {"); 286 size_t end_g = ss.str().find('}', beg_g); 287 288 ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; 289 290 std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {"))); 291 292 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u1[]") != std::string::npos); 293 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i8[]") != std::string::npos); 294 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u8[]") != std::string::npos); 295 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i16[]") != std::string::npos); 296 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u16[]") != std::string::npos); 297 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i32[]") != std::string::npos); 298 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u32[]") != std::string::npos); 299 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, f32[]") != std::string::npos); 300 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, f64[]") != std::string::npos); 301 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, i64[]") != std::string::npos); 302 EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u64[]") != std::string::npos); 303} 304 305TEST(instructions_test, test_debug_info) 306{ 307 Disassembler d; 308 309 std::stringstream ss; 310 d.Disassemble(std::string(DISASM_BIN_DIR) + "instructions.bc"); 311 d.CollectInfo(); 312 d.Serialize(ss, true, true); 313 314 size_t beg_g = ss.str().find("g() <static> {"); 315 size_t end_g = ss.str().find('}', beg_g); 316 317 ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; 318 319 std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {"))); 320 321 ASSERT_NE(body_g.find("# LINE_NUMBER_TABLE:"), std::string::npos); 322 ASSERT_NE(body_g.find("#\tline 26: 0\n"), std::string::npos); 323 324 size_t code_start = body_g.find("# CODE:\n"); 325 ASSERT_NE(code_start, std::string::npos) << "Code section in function g not found"; 326 size_t code_end = body_g.find("\n\n"); // First gap in function body is code section end 327 ASSERT_NE(code_end, std::string::npos) << "Gap after code section in function g not found"; 328 ASSERT_LT(code_start, code_end); 329 std::string instructions = 330 body_g.substr(code_start + strlen("# CODE:\n"), code_end + 1 - (code_start + strlen("# CODE:\n"))); 331 size_t instruction_count = std::count(instructions.begin(), instructions.end(), '\n'); 332 333 const ProgInfo &prog_info = d.GetProgInfo(); 334 auto g_it = prog_info.methods_info.find("g:()"); 335 ASSERT_NE(g_it, prog_info.methods_info.end()); 336 // In case of pandasm the table should contain entry on each instruction 337 ASSERT_EQ(g_it->second.line_number_table.size(), instruction_count); 338 339 // There should be no local variables for panda assembler 340 ASSERT_EQ(body_g.find("# LOCAL_VARIABLE_TABLE:"), std::string::npos); 341} 342 343#undef DISASM_BIN_DIR 344