/*
 * Copyright (c) 2010 ftofficer <ftofficer.zhangc@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/*
    Check the instruction before an address.
 */
inline
bool CheckOpCode(const unsigned char* address, int bytes_before,
                 const unsigned char opcode, const unsigned char opcode2,
                 const char* what)
{
	(what);
    if ( *(address-bytes_before) == opcode &&
        (opcode2 == 0 || *(address-bytes_before+1) == opcode2) )
    {
        return true;
    }

    return false;
}

bool IsAddressAfterCallInstruction(void* address)
{
    const unsigned char* addr = (const unsigned char*)address;

    return CheckOpCode(addr, 5, 0xE8, 0, "CALL rel32") ||

        CheckOpCode(addr, 6, 0xFF, 0x15, "CALL dword ptr [abs32]") ||
        CheckOpCode(addr, 3, 0xFF, 0x14, "CALL dword ptr [REG*SCALE+BASE]") ||
        CheckOpCode(addr, 2, 0xFF, 0x10, "CALL dword ptr [EAX]") ||
        CheckOpCode(addr, 2, 0xFF, 0x11, "CALL dword ptr [ECX]") ||
        CheckOpCode(addr, 2, 0xFF, 0x12, "CALL dword ptr [EDX]") ||
        CheckOpCode(addr, 2, 0xFF, 0x13, "CALL dword ptr [EBX]") ||
        CheckOpCode(addr, 2, 0xFF, 0x16, "CALL dword ptr [ESI]") ||
        CheckOpCode(addr, 2, 0xFF, 0x17, "CALL dword ptr [EDI]") ||

        CheckOpCode(addr, 4, 0xFF, 0x54, "CALL dword ptr [REG*SCALE+BASE+off8]") ||
        CheckOpCode(addr, 3, 0xFF, 0x50, "CALL dword ptr [EAX+off8]") ||
        CheckOpCode(addr, 3, 0xFF, 0x51, "CALL dword ptr [ECX+off8]") ||
        CheckOpCode(addr, 3, 0xFF, 0x52, "CALL dword ptr [EDX+off8]") ||
        CheckOpCode(addr, 3, 0xFF, 0x53, "CALL dword ptr [EBX+off8]") ||
        CheckOpCode(addr, 3, 0xFF, 0x55, "CALL dword ptr [EBP+off8]") ||
        CheckOpCode(addr, 3, 0xFF, 0x56, "CALL dword ptr [ESI+off8]") ||
        CheckOpCode(addr, 3, 0xFF, 0x57, "CALL dword ptr [EDI+off8]") ||

        CheckOpCode(addr, 7, 0xFF, 0x94, "CALL dword ptr [REG*SCALE+BASE+off32]") ||
        CheckOpCode(addr, 6, 0xFF, 0x90, "CALL dword ptr [EAX+off32]") ||
        CheckOpCode(addr, 6, 0xFF, 0x91, "CALL dword ptr [ECX+off32]") ||
        CheckOpCode(addr, 6, 0xFF, 0x92, "CALL dword ptr [EDX+off32]") ||
        CheckOpCode(addr, 6, 0xFF, 0x93, "CALL dword ptr [EBX+off32]") ||
        CheckOpCode(addr, 6, 0xFF, 0x95, "CALL dword ptr [EBP+off32]") ||
        CheckOpCode(addr, 6, 0xFF, 0x96, "CALL dword ptr [ESI+off32]") ||
        CheckOpCode(addr, 6, 0xFF, 0x97, "CALL dword ptr [EDI+off32]") ||

        CheckOpCode(addr, 2, 0xFF, 0xD0, "CALL EAX") ||
        CheckOpCode(addr, 2, 0xFF, 0xD1, "CALL ECX") ||
        CheckOpCode(addr, 2, 0xFF, 0xD2, "CALL EDX") ||
        CheckOpCode(addr, 2, 0xFF, 0xD3, "CALL EBX") ||
        CheckOpCode(addr, 2, 0xFF, 0xD4, "CALL ESP") ||
        CheckOpCode(addr, 2, 0xFF, 0xD5, "CALL EBP") ||
        CheckOpCode(addr, 2, 0xFF, 0xD6, "CALL ESI") ||
        CheckOpCode(addr, 2, 0xFF, 0xD7, "CALL EDI") ||

        CheckOpCode(addr, 7, 0x9A, 0, "CALL FAR seg16:abs32");
}
