/ externals / zydis / tools / ZydisTestEncoderAbsolute.c
ZydisTestEncoderAbsolute.c
  1  /***************************************************************************************************
  2  
  3    Zyan Disassembler Library (Zydis)
  4  
  5    Original Author : Mappa
  6  
  7   * Permission is hereby granted, free of charge, to any person obtaining a copy
  8   * of this software and associated documentation files (the "Software"), to deal
  9   * in the Software without restriction, including without limitation the rights
 10   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11   * copies of the Software, and to permit persons to whom the Software is
 12   * furnished to do so, subject to the following conditions:
 13   *
 14   * The above copyright notice and this permission notice shall be included in all
 15   * copies or substantial portions of the Software.
 16   *
 17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 23   * SOFTWARE.
 24  
 25  ***************************************************************************************************/
 26  
 27  /**
 28   * @file
 29   *
 30   * Test set for `ZydisEncoderEncodeInstructionAbsolute`.
 31   */
 32  
 33  #include <inttypes.h>
 34  #include <Zycore/LibC.h>
 35  #include <Zydis/Zydis.h>
 36  #include <Zydis/Internal/EncoderData.h>
 37  
 38  /* ============================================================================================== */
 39  /* Enums and Types                                                                                */
 40  /* ============================================================================================== */
 41  
 42  #define TEST_RUNTIME_ADDRESS 0x00004000
 43  
 44  typedef struct Iterator_
 45  {
 46      ZyanU32 value;
 47      ZyanU32 limit;
 48  } Iterator;
 49  
 50  /* ============================================================================================== */
 51  /* Helper functions                                                                               */
 52  /* ============================================================================================== */
 53  
 54  static ZyanBool AdvanceIterators(Iterator *iterators, ZyanUSize count)
 55  {
 56      if (!iterators || !count)
 57      {
 58          return ZYAN_FALSE;
 59      }
 60  
 61      for (ZyanUSize i = 0; i < count; ++i)
 62      {
 63          Iterator *iterator = &iterators[count - 1 - i];
 64          iterator->value++;
 65          if (iterator->value < iterator->limit)
 66          {
 67              return ZYAN_TRUE;
 68          }
 69          iterator->value = 0;
 70      }
 71  
 72      return ZYAN_FALSE;
 73  }
 74  
 75  static void PrintBytes(ZyanU8 *bytes, ZyanUSize count)
 76  {
 77      for (ZyanUSize i = 0; i < count; ++i)
 78      {
 79          ZYAN_PRINTF("%02X ", bytes[i]);
 80      }
 81  }
 82  
 83  /* ============================================================================================== */
 84  /* Tests                                                                                          */
 85  /* ============================================================================================== */
 86  
 87  static ZyanBool RunTest(ZydisEncoderRequest *req, const char *test_name, ZyanU8 rel_op_index,
 88      ZyanBool is_rip_rel_test)
 89  {
 90      ZyanU8 instruction1[ZYDIS_MAX_INSTRUCTION_LENGTH];
 91      ZyanUSize length1 = sizeof(instruction1);
 92      if (ZYAN_FAILED(ZydisEncoderEncodeInstruction(req, instruction1, &length1)))
 93      {
 94          ZYAN_PRINTF("%s: NOT ENCODABLE\n", test_name);
 95          return ZYAN_TRUE;
 96      }
 97  
 98      ZydisDecoder decoder;
 99      ZydisStackWidth stack_width;
100      ZydisDecodedInstruction dec_instruction;
101      ZydisDecodedOperand dec_operands[ZYDIS_MAX_OPERAND_COUNT];
102      switch (req->machine_mode)
103      {
104      case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
105          stack_width = ZYDIS_STACK_WIDTH_16;
106          break;
107      case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
108          stack_width = ZYDIS_STACK_WIDTH_32;
109          break;
110      case ZYDIS_MACHINE_MODE_LONG_64:
111          stack_width = ZYDIS_STACK_WIDTH_64;
112          break;
113      default:
114          ZYAN_UNREACHABLE;
115      }
116      if (ZYAN_FAILED(ZydisDecoderInit(&decoder, req->machine_mode, stack_width)))
117      {
118          ZYAN_PRINTF("%s: FAILED TO INITIALIZE DECODER\n", test_name);
119          return ZYAN_FALSE;
120      }
121      if (ZYAN_FAILED(ZydisDecoderDecodeFull(&decoder, instruction1, sizeof(instruction1),
122          &dec_instruction, dec_operands)))
123      {
124          ZYAN_PRINTF("%s: FAILED TO DECODE INSTRUCTION\n", test_name);
125          return ZYAN_FALSE;
126      }
127      ZyanU64 absolute_address = 0;
128      if (ZYAN_FAILED(ZydisCalcAbsoluteAddress(&dec_instruction, &dec_operands[rel_op_index],
129          TEST_RUNTIME_ADDRESS, &absolute_address)))
130      {
131          ZYAN_PRINTF("%s: FAILED TO COMPUTE ABSOLUTE ADDRESS\n", test_name);
132          return ZYAN_FALSE;
133      }
134      if (is_rip_rel_test)
135      {
136          ZYAN_ASSERT(req->operands[rel_op_index].type == ZYDIS_OPERAND_TYPE_MEMORY);
137          req->operands[rel_op_index].mem.displacement = absolute_address;
138      }
139      else
140      {
141          ZYAN_ASSERT(req->operands[rel_op_index].type == ZYDIS_OPERAND_TYPE_IMMEDIATE);
142          req->operands[rel_op_index].imm.u = absolute_address;
143      }
144  
145      ZyanU8 instruction2[ZYDIS_MAX_INSTRUCTION_LENGTH];
146      ZyanUSize length2 = sizeof(instruction2);
147      if (ZYAN_FAILED(ZydisEncoderEncodeInstructionAbsolute(req, instruction2, &length2,
148          TEST_RUNTIME_ADDRESS)))
149      {
150          ZYAN_PRINTF("%s: FAILED TO ENCODE INSTRUCTION\n", test_name);
151          return ZYAN_FALSE;
152      }
153      ZYAN_PRINTF("%s: ", test_name);
154      PrintBytes(instruction1, length1);
155      if ((length1 != length2) || ZYAN_MEMCMP(instruction1, instruction2, length1))
156      {
157          ZYAN_PRINTF("!= ");
158          PrintBytes(instruction2, length2);
159          ZYAN_PRINTF("\n");
160          return ZYAN_FALSE;
161      }
162      ZYAN_PRINTF("\n");
163      return ZYAN_TRUE;
164  }
165  
166  static ZyanBool RunBranchingTests()
167  {
168      static const ZydisMnemonic instructions[] =
169      {
170          ZYDIS_MNEMONIC_CALL,
171          ZYDIS_MNEMONIC_JZ,
172          ZYDIS_MNEMONIC_JCXZ,
173          ZYDIS_MNEMONIC_JECXZ,
174          ZYDIS_MNEMONIC_JRCXZ,
175          ZYDIS_MNEMONIC_JKZD,
176          ZYDIS_MNEMONIC_JMP,
177      };
178      static const ZydisMachineMode modes[] =
179      {
180          ZYDIS_MACHINE_MODE_LONG_COMPAT_16,
181          ZYDIS_MACHINE_MODE_LONG_COMPAT_32,
182          ZYDIS_MACHINE_MODE_LONG_64,
183      };
184      static const char *str_modes[] =
185      {
186          "M16",
187          "M32",
188          "M64",
189      };
190      static const ZyanU64 rels[] =
191      {
192          0x11,
193          0x2222,
194          0x44444444,
195      };
196      static const ZydisBranchType branch_types[] =
197      {
198          ZYDIS_BRANCH_TYPE_NONE,
199          ZYDIS_BRANCH_TYPE_SHORT,
200          ZYDIS_BRANCH_TYPE_NEAR,
201      };
202      static const char *str_branch_types[] =
203      {
204          "T0",
205          "TS",
206          "TN",
207      };
208      static const ZydisBranchWidth branch_widths[] =
209      {
210          ZYDIS_BRANCH_WIDTH_NONE,
211          ZYDIS_BRANCH_WIDTH_8,
212          ZYDIS_BRANCH_WIDTH_16,
213          ZYDIS_BRANCH_WIDTH_32,
214          ZYDIS_BRANCH_WIDTH_64,
215      };
216      static const char *str_branch_widths[] =
217      {
218          "W00",
219          "W08",
220          "W16",
221          "W32",
222          "W64",
223      };
224      static const ZydisInstructionAttributes prefixes[] = {
225          0,
226          ZYDIS_ATTRIB_HAS_BRANCH_TAKEN,
227      };
228      static const char *str_prefixes[] =
229      {
230          "P00",
231          "PBT",
232      };
233      static const ZydisAddressSizeHint address_hints[] =
234      {
235          ZYDIS_ADDRESS_SIZE_HINT_NONE,
236          ZYDIS_ADDRESS_SIZE_HINT_16,
237          ZYDIS_ADDRESS_SIZE_HINT_32,
238          ZYDIS_ADDRESS_SIZE_HINT_64,
239      };
240      static const char *str_address_hints[] =
241      {
242          "AH00",
243          "AH16",
244          "AH32",
245          "AH64",
246      };
247      static const ZydisOperandSizeHint operand_hints[] =
248      {
249          ZYDIS_OPERAND_SIZE_HINT_NONE,
250          ZYDIS_OPERAND_SIZE_HINT_8,
251          ZYDIS_OPERAND_SIZE_HINT_16,
252          ZYDIS_OPERAND_SIZE_HINT_32,
253          ZYDIS_OPERAND_SIZE_HINT_64,
254      };
255      static const char *str_operand_hints[] =
256      {
257          "OH00",
258          "OH08",
259          "OH16",
260          "OH32",
261          "OH64",
262      };
263  
264      ZydisEncoderRequest req;
265      ZyanBool all_passed = ZYAN_TRUE;
266      Iterator iter_branches[6] =
267      {
268          { 0, ZYAN_ARRAY_LENGTH(instructions) },
269          { 0, ZYAN_ARRAY_LENGTH(modes) },
270          { 0, ZYAN_ARRAY_LENGTH(rels) },
271          { 0, ZYAN_ARRAY_LENGTH(branch_types) },
272          { 0, ZYAN_ARRAY_LENGTH(branch_widths) },
273          { 0, ZYAN_ARRAY_LENGTH(prefixes) },
274      };
275      do
276      {
277          ZydisMnemonic mnemonic = instructions[iter_branches[0].value];
278          ZydisMachineMode mode = modes[iter_branches[1].value];
279          ZyanU64 rel = rels[iter_branches[2].value];
280          ZydisBranchType branch_type = branch_types[iter_branches[3].value];
281          ZydisBranchWidth branch_width = branch_widths[iter_branches[4].value];
282          ZydisInstructionAttributes prefix = prefixes[iter_branches[5].value];
283  
284          const ZydisEncoderRelInfo *rel_info = ZydisGetRelInfo(mnemonic);
285          ZYAN_ASSERT(rel_info);
286          if (!rel_info->accepts_branch_hints && iter_branches[5].value != 0)
287          {
288              continue;
289          }
290  
291          ZYAN_MEMSET(&req, 0, sizeof(req));
292          req.machine_mode = mode;
293          req.mnemonic = mnemonic;
294          req.prefixes = prefix;
295          req.branch_type = branch_type;
296          req.branch_width = branch_width;
297          req.operand_count = 1;
298          req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
299          req.operands[0].imm.u = rel;
300          if (mnemonic != ZYDIS_MNEMONIC_JKZD)
301          {
302              req.operand_count = 1;
303              req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
304              req.operands[0].imm.u = rel;
305          }
306          else
307          {
308              req.operand_count = 2;
309              req.operands[0].type = ZYDIS_OPERAND_TYPE_REGISTER;
310              req.operands[0].reg.value = ZYDIS_REGISTER_K1;
311              req.operands[1].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
312              req.operands[1].imm.u = rel;
313          }
314  
315          char test_name[256];
316          snprintf(test_name, sizeof(test_name), "%s:%s:%08" PRIX64 ":%s:%s:%s",
317              ZydisMnemonicGetString(mnemonic),
318              str_modes[iter_branches[1].value],
319              rel,
320              str_branch_types[iter_branches[3].value],
321              str_branch_widths[iter_branches[4].value],
322              str_prefixes[iter_branches[5].value]);
323          all_passed &= RunTest(&req, test_name, (mnemonic != ZYDIS_MNEMONIC_JKZD) ? 0 : 1,
324              ZYAN_FALSE);
325      } while (AdvanceIterators(iter_branches, ZYAN_ARRAY_LENGTH(iter_branches)));
326  
327      Iterator iter_asz_branches[4] =
328      {
329          { 0, ZYAN_ARRAY_LENGTH(modes) },
330          { 0, ZYAN_ARRAY_LENGTH(branch_types) },
331          { 0, ZYAN_ARRAY_LENGTH(branch_widths) },
332          { 0, ZYAN_ARRAY_LENGTH(address_hints) },
333      };
334      do
335      {
336          ZydisMachineMode mode = modes[iter_asz_branches[0].value];
337          ZydisBranchType branch_type = branch_types[iter_asz_branches[1].value];
338          ZydisBranchWidth branch_width = branch_widths[iter_asz_branches[2].value];
339          ZydisAddressSizeHint address_hint = address_hints[iter_asz_branches[3].value];
340  
341          ZYAN_MEMSET(&req, 0, sizeof(req));
342          req.machine_mode = mode;
343          req.mnemonic = ZYDIS_MNEMONIC_LOOP;
344          req.branch_type = branch_type;
345          req.branch_width = branch_width;
346          req.address_size_hint = address_hint;
347          req.operand_count = 1;
348          req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
349          req.operands[0].imm.u = 0x55;
350  
351          char test_name[256];
352          snprintf(test_name, sizeof(test_name), "%s:%s:%s:%s:%s",
353              ZydisMnemonicGetString(req.mnemonic),
354              str_modes[iter_asz_branches[0].value],
355              str_branch_types[iter_asz_branches[1].value],
356              str_branch_widths[iter_asz_branches[2].value],
357              str_address_hints[iter_asz_branches[3].value]);
358          all_passed &= RunTest(&req, test_name, 0, ZYAN_FALSE);
359      } while (AdvanceIterators(iter_asz_branches, ZYAN_ARRAY_LENGTH(iter_asz_branches)));
360  
361      Iterator iter_osz_branches[3] =
362      {
363          { 0, ZYAN_ARRAY_LENGTH(modes) },
364          { 0, ZYAN_ARRAY_LENGTH(rels) },
365          { 0, ZYAN_ARRAY_LENGTH(operand_hints) },
366      };
367      do
368      {
369          ZydisMachineMode mode = modes[iter_osz_branches[0].value];
370          ZyanU64 rel = rels[iter_osz_branches[1].value];
371          ZydisOperandSizeHint operand_hint = operand_hints[iter_osz_branches[2].value];
372  
373          ZYAN_MEMSET(&req, 0, sizeof(req));
374          req.machine_mode = mode;
375          req.mnemonic = ZYDIS_MNEMONIC_XBEGIN;
376          req.operand_size_hint = operand_hint;
377          req.operand_count = 1;
378          req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
379          req.operands[0].imm.u = rel;
380  
381          char test_name[256];
382          snprintf(test_name, sizeof(test_name), "%s:%s:%08" PRIX64 ":%s",
383              ZydisMnemonicGetString(req.mnemonic),
384              str_modes[iter_osz_branches[0].value],
385              rel,
386              str_operand_hints[iter_osz_branches[2].value]);
387          all_passed &= RunTest(&req, test_name, 0, ZYAN_FALSE);
388      } while (AdvanceIterators(iter_osz_branches, ZYAN_ARRAY_LENGTH(iter_osz_branches)));
389  
390      return all_passed;
391  }
392  
393  static ZyanBool RunRipRelativeTests()
394  {
395      ZydisEncoderRequest req;
396      ZyanBool all_passed = ZYAN_TRUE;
397  
398      // Basic test
399      ZYAN_MEMSET(&req, 0, sizeof(req));
400      req.machine_mode = ZYDIS_MACHINE_MODE_LONG_64;
401      req.mnemonic = ZYDIS_MNEMONIC_XOR;
402      req.operand_count = 2;
403      req.operands[0].type = ZYDIS_OPERAND_TYPE_REGISTER;
404      req.operands[0].reg.value = ZYDIS_REGISTER_RAX;
405      req.operands[1].type = ZYDIS_OPERAND_TYPE_MEMORY;
406      req.operands[1].mem.base = ZYDIS_REGISTER_RIP;
407      req.operands[1].mem.displacement = 0x66666666;
408      req.operands[1].mem.size = 8;
409      all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 1, ZYAN_TRUE);
410  
411      // Displacement + immediate
412      ZYAN_MEMSET(&req, 0, sizeof(req));
413      req.machine_mode = ZYDIS_MACHINE_MODE_LONG_64;
414      req.mnemonic = ZYDIS_MNEMONIC_CMP;
415      req.operand_count = 2;
416      req.operands[0].type = ZYDIS_OPERAND_TYPE_MEMORY;
417      req.operands[0].mem.base = ZYDIS_REGISTER_RIP;
418      req.operands[0].mem.displacement = 0x66666666;
419      req.operands[0].mem.size = 4;
420      req.operands[1].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
421      req.operands[1].imm.u = 0x11223344;
422      all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 0, ZYAN_TRUE);
423  
424      // EIP-relative
425      ZYAN_MEMSET(&req, 0, sizeof(req));
426      req.machine_mode = ZYDIS_MACHINE_MODE_LONG_64;
427      req.mnemonic = ZYDIS_MNEMONIC_SUB;
428      req.operand_count = 2;
429      req.operands[0].type = ZYDIS_OPERAND_TYPE_MEMORY;
430      req.operands[0].mem.base = ZYDIS_REGISTER_EIP;
431      req.operands[0].mem.displacement = 0x66666666;
432      req.operands[0].mem.size = 4;
433      req.operands[1].type = ZYDIS_OPERAND_TYPE_REGISTER;
434      req.operands[1].reg.value = ZYDIS_REGISTER_EBX;
435      all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 0, ZYAN_TRUE);
436  
437      return all_passed;
438  }
439  
440  /* ============================================================================================== */
441  /* Entry point                                                                                    */
442  /* ============================================================================================== */
443  
444  int main(void)
445  {
446      ZyanBool all_passed = ZYAN_TRUE;
447      ZYAN_PRINTF("Branching tests:\n");
448      all_passed &= RunBranchingTests();
449      ZYAN_PRINTF("\nEIP/RIP-relative tests:\n");
450      all_passed &= RunRipRelativeTests();
451      ZYAN_PRINTF("\n");
452      if (!all_passed)
453      {
454          ZYAN_PRINTF("SOME TESTS FAILED\n");
455          return 1;
456      }
457  
458      ZYAN_PRINTF("ALL TESTS PASSED\n");
459      return 0;
460  }
461  
462  /* ============================================================================================== */