Home | History | Annotate | Download | only in processor
      1 // Copyright (c) 2010, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
     29 
     30 #include <unistd.h>
     31 
     32 #include "breakpad_googletest_includes.h"
     33 #include "processor/disassembler_x86.h"
     34 #include "third_party/libdisasm/libdis.h"
     35 
     36 namespace {
     37 
     38 using google_breakpad::DisassemblerX86;
     39 
     40 unsigned char just_return[] = "\xc3";  // retn
     41 
     42 unsigned char invalid_instruction[] = "\x00";  // invalid
     43 
     44 unsigned char read_eax_jmp_eax[] =
     45     "\x8b\x18"                  // mov ebx, [eax];
     46     "\x33\xc9"                  // xor ebx, ebx;
     47     "\xff\x20"                  // jmp eax;
     48     "\xc3";                     // retn;
     49 
     50 unsigned char write_eax_arg_to_call[] =
     51     "\x89\xa8\x00\x02\x00\x00"  // mov [eax+200], ebp;
     52     "\xc1\xeb\x02"              // shr ebx, 2;
     53     "\x50"                      // push eax;
     54     "\xe8\xd1\x24\x77\x88"      // call something;
     55     "\xc3";                     // retn;
     56 
     57 unsigned char read_edi_stosb[] =
     58     "\x8b\x07"                  // mov eax, [edi];
     59     "\x8b\xc8"                  // mov ecx, eax;
     60     "\xf3\xaa"                  // rep stosb;
     61     "\xc3";                     // retn;
     62 
     63 unsigned char read_clobber_write[] =
     64     "\x03\x18"                  // add ebx, [eax];
     65     "\x8b\xc1"                  // mov eax, ecx;
     66     "\x89\x10"                  // mov [eax], edx;
     67     "\xc3";                     // retn;
     68 
     69 unsigned char read_xchg_write[] =
     70     "\x03\x18"                  // add ebx, [eax];
     71     "\x91"                      // xchg eax, ecx;
     72     "\x89\x18"                  // mov [eax], ebx;
     73     "\x89\x11"                  // mov [ecx], edx;
     74     "\xc3";                     // retn;
     75 
     76 unsigned char read_cmp[] =
     77     "\x03\x18"                  // add ebx, [eax];
     78     "\x83\xf8\x00"              // cmp eax, 0;
     79     "\x74\x04"                  // je +4;
     80     "\xc3";                     // retn;
     81 
     82 TEST(DisassemblerX86Test, SimpleReturnInstruction) {
     83   DisassemblerX86 dis(just_return, sizeof(just_return)-1, 0);
     84   EXPECT_EQ(1U, dis.NextInstruction());
     85   EXPECT_TRUE(dis.currentInstructionValid());
     86   EXPECT_EQ(0U, dis.flags());
     87   EXPECT_TRUE(dis.endOfBlock());
     88   EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup());
     89   const libdis::x86_insn_t* instruction = dis.currentInstruction();
     90   EXPECT_EQ(libdis::insn_controlflow, instruction->group);
     91   EXPECT_EQ(libdis::insn_return, instruction->type);
     92   EXPECT_EQ(0U, dis.NextInstruction());
     93   EXPECT_FALSE(dis.currentInstructionValid());
     94   EXPECT_EQ(NULL, dis.currentInstruction());
     95 }
     96 
     97 TEST(DisassemblerX86Test, SimpleInvalidInstruction) {
     98   DisassemblerX86 dis(invalid_instruction, sizeof(invalid_instruction)-1, 0);
     99   EXPECT_EQ(0U, dis.NextInstruction());
    100   EXPECT_FALSE(dis.currentInstructionValid());
    101 }
    102 
    103 TEST(DisassemblerX86Test, BadReadLeadsToBranch) {
    104   DisassemblerX86 dis(read_eax_jmp_eax, sizeof(read_eax_jmp_eax)-1, 0);
    105   EXPECT_EQ(2U, dis.NextInstruction());
    106   EXPECT_TRUE(dis.currentInstructionValid());
    107   EXPECT_EQ(0U, dis.flags());
    108   EXPECT_FALSE(dis.endOfBlock());
    109   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    110   EXPECT_TRUE(dis.setBadRead());
    111   EXPECT_EQ(2U, dis.NextInstruction());
    112   EXPECT_TRUE(dis.currentInstructionValid());
    113   EXPECT_EQ(0U, dis.flags());
    114   EXPECT_FALSE(dis.endOfBlock());
    115   EXPECT_EQ(libdis::insn_logic, dis.currentInstructionGroup());
    116   EXPECT_EQ(2U, dis.NextInstruction());
    117   EXPECT_TRUE(dis.currentInstructionValid());
    118   EXPECT_EQ(google_breakpad::DISX86_BAD_BRANCH_TARGET, dis.flags());
    119   EXPECT_FALSE(dis.endOfBlock());
    120   EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup());
    121 }
    122 
    123 TEST(DisassemblerX86Test, BadWriteLeadsToPushedArg) {
    124   DisassemblerX86 dis(write_eax_arg_to_call,
    125                       sizeof(write_eax_arg_to_call)-1, 0);
    126   EXPECT_EQ(6U, dis.NextInstruction());
    127   EXPECT_TRUE(dis.currentInstructionValid());
    128   EXPECT_EQ(0U, dis.flags());
    129   EXPECT_FALSE(dis.endOfBlock());
    130   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    131   EXPECT_TRUE(dis.setBadWrite());
    132   EXPECT_EQ(3U, dis.NextInstruction());
    133   EXPECT_TRUE(dis.currentInstructionValid());
    134   EXPECT_EQ(0U, dis.flags());
    135   EXPECT_FALSE(dis.endOfBlock());
    136   EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup());
    137   EXPECT_EQ(1U, dis.NextInstruction());
    138   EXPECT_TRUE(dis.currentInstructionValid());
    139   EXPECT_EQ(0U, dis.flags());
    140   EXPECT_FALSE(dis.endOfBlock());
    141   EXPECT_EQ(5U, dis.NextInstruction());
    142   EXPECT_TRUE(dis.currentInstructionValid());
    143   EXPECT_EQ(google_breakpad::DISX86_BAD_ARGUMENT_PASSED, dis.flags());
    144   EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup());
    145   EXPECT_FALSE(dis.endOfBlock());
    146 }
    147 
    148 
    149 TEST(DisassemblerX86Test, BadReadLeadsToBlockWrite) {
    150   DisassemblerX86 dis(read_edi_stosb, sizeof(read_edi_stosb)-1, 0);
    151   EXPECT_EQ(2U, dis.NextInstruction());
    152   EXPECT_TRUE(dis.currentInstructionValid());
    153   EXPECT_EQ(0U, dis.flags());
    154   EXPECT_FALSE(dis.endOfBlock());
    155   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    156   EXPECT_TRUE(dis.setBadRead());
    157   EXPECT_EQ(2U, dis.NextInstruction());
    158   EXPECT_TRUE(dis.currentInstructionValid());
    159   EXPECT_EQ(0U, dis.flags());
    160   EXPECT_FALSE(dis.endOfBlock());
    161   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    162   EXPECT_EQ(2U, dis.NextInstruction());
    163   EXPECT_TRUE(dis.currentInstructionValid());
    164   EXPECT_EQ(google_breakpad::DISX86_BAD_BLOCK_WRITE, dis.flags());
    165   EXPECT_FALSE(dis.endOfBlock());
    166   EXPECT_EQ(libdis::insn_string, dis.currentInstructionGroup());
    167 }
    168 
    169 TEST(DisassemblerX86Test, BadReadClobberThenWrite) {
    170   DisassemblerX86 dis(read_clobber_write, sizeof(read_clobber_write)-1, 0);
    171   EXPECT_EQ(2U, dis.NextInstruction());
    172   EXPECT_TRUE(dis.currentInstructionValid());
    173   EXPECT_EQ(0U, dis.flags());
    174   EXPECT_FALSE(dis.endOfBlock());
    175   EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup());
    176   EXPECT_TRUE(dis.setBadRead());
    177   EXPECT_EQ(2U, dis.NextInstruction());
    178   EXPECT_TRUE(dis.currentInstructionValid());
    179   EXPECT_EQ(0U, dis.flags());
    180   EXPECT_FALSE(dis.endOfBlock());
    181   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    182   EXPECT_EQ(2U, dis.NextInstruction());
    183   EXPECT_TRUE(dis.currentInstructionValid());
    184   EXPECT_EQ(0U, dis.flags());
    185   EXPECT_FALSE(dis.endOfBlock());
    186   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    187 }
    188 
    189 TEST(DisassemblerX86Test, BadReadXCHGThenWrite) {
    190   DisassemblerX86 dis(read_xchg_write, sizeof(read_xchg_write)-1, 0);
    191   EXPECT_EQ(2U, dis.NextInstruction());
    192   EXPECT_TRUE(dis.currentInstructionValid());
    193   EXPECT_EQ(0U, dis.flags());
    194   EXPECT_FALSE(dis.endOfBlock());
    195   EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup());
    196   EXPECT_TRUE(dis.setBadRead());
    197   EXPECT_EQ(1U, dis.NextInstruction());
    198   EXPECT_TRUE(dis.currentInstructionValid());
    199   EXPECT_EQ(0U, dis.flags());
    200   EXPECT_FALSE(dis.endOfBlock());
    201   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    202   EXPECT_EQ(2U, dis.NextInstruction());
    203   EXPECT_TRUE(dis.currentInstructionValid());
    204   EXPECT_EQ(0U, dis.flags());
    205   EXPECT_FALSE(dis.endOfBlock());
    206   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    207   EXPECT_EQ(2U, dis.NextInstruction());
    208   EXPECT_TRUE(dis.currentInstructionValid());
    209   EXPECT_EQ(google_breakpad::DISX86_BAD_WRITE, dis.flags());
    210   EXPECT_FALSE(dis.endOfBlock());
    211   EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup());
    212 }
    213 
    214 TEST(DisassemblerX86Test, BadReadThenCMP) {
    215   DisassemblerX86 dis(read_cmp, sizeof(read_cmp)-1, 0);
    216   EXPECT_EQ(2U, dis.NextInstruction());
    217   EXPECT_TRUE(dis.currentInstructionValid());
    218   EXPECT_EQ(0U, dis.flags());
    219   EXPECT_FALSE(dis.endOfBlock());
    220   EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup());
    221   EXPECT_TRUE(dis.setBadRead());
    222   EXPECT_EQ(3U, dis.NextInstruction());
    223   EXPECT_TRUE(dis.currentInstructionValid());
    224   EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags());
    225   EXPECT_FALSE(dis.endOfBlock());
    226   EXPECT_EQ(libdis::insn_comparison, dis.currentInstructionGroup());
    227   EXPECT_EQ(2U, dis.NextInstruction());
    228   EXPECT_TRUE(dis.currentInstructionValid());
    229   EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags());
    230   EXPECT_FALSE(dis.endOfBlock());
    231   EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup());
    232 }
    233 }
    234