Exemple #1
0
void CboValidatorCore::ValidateBlob()
{
	AssertBytesRemaining(sizeof(Value32) + sizeof(Value16));
	const size_t blobStart = GetPosition();
	const size_t blobSize = ReadValue32().mUInt;
	const size_t blobEnd = blobStart + blobSize;
	const size_t idIndex = ReadValue16().mUShort;

	AssertBytesRemaining(blobSize - (GetPosition() - blobStart));

	if (idIndex == mResult.mListBlobIdIndex)
	{
		ValidateListBlob();
	}
	else if (idIndex == mResult.mFunctionBlobIdIndex)
	{
		ValidateFunctionBlob(blobEnd);
	}
	else if (idIndex == mResult.mDataBlobIdIndex)
	{
		ValidateDataBlob(blobEnd);
	}
	else
	{
		SetPosition(blobEnd);
	}

	if (GetPosition() != blobEnd)
	{
		CboIsInvalid();
	}
}
Exemple #2
0
void DisassemblerCore::Disassemble()
{
	// Skip some header information that is already included in the validation result.
	Skip((2 * sizeof(Value32)) + (7 * sizeof(Value16)));

	mOutStream.Print("Version %" BOND_PRIu32 ".%" BOND_PRIu32 "\n", mValidationResult.mMajorVersion, mValidationResult.mMinorVersion);
	mOutStream.Print("Pointer size: %d bits\n", (mValidationResult.mPointerSize == POINTER_64BIT) ? 64 : 32);

	for (size_t i = 0; i < mValidationResult.mValue32Count; ++i)
	{
		mValue32Table[i] = ReadValue32();
	}

	for (size_t i = 0; i < mValidationResult.mValue64Count; ++i)
	{
		mValue64Table[i] = ReadValue64();
	}

	char *stringBytes = mStringBytes.data();
	for (size_t i = 0; i < mValidationResult.mStringCount; ++i)
	{
		const size_t length = ReadValue16().mUShort;
		mStringTable[i] = StringView(stringBytes, length);
		mCboStream.Read(stringBytes, length);
		stringBytes += length;
		*stringBytes++ = '\0';
	}

	QualifiedName *name = mQualifiedNameTable.data();
	const char **element = mQualifiedNameElementTable.data();
	for (size_t i = 0; i < mValidationResult.mQualifiedNameCount; ++i)
	{
		*name++ = QualifiedName(element);
		const size_t numElements = ReadValue16().mUShort;
		for (size_t j = 0; j < numElements; ++j)
		{
			const size_t elementIndex = ReadValue16().mUShort;
			*element++ = mStringTable[elementIndex].GetString();
		}
		*element++ = nullptr;
	}

	DisassembleBlob();
}
Exemple #3
0
size_t CboValidatorCore::ValidateQualifiedNameIndex()
{
	AssertBytesRemaining(sizeof(Value16));
	const size_t nameIndex = ReadValue16().mUShort;
	if (nameIndex >= mResult.mQualifiedNameCount)
	{
		CboIsInvalid();
	}
	return nameIndex;
}
Exemple #4
0
void DisassemblerCore::DisassembleParamListSignature()
{
	const size_t numElements = ReadValue16().mUShort;
	for (size_t i = 0; i < numElements; ++i)
	{
		// Skip the frame pointer offset.
		Skip(sizeof(Value32));
		if (i > 0)
		{
			mOutStream.Print(", ");
		}
		DisassembleSizeAndType();
	}
}
Exemple #5
0
void CboValidatorCore::ValidateParamListSignature()
{
	AssertBytesRemaining(sizeof(Value16));
	const size_t numParams = ReadValue16().mUShort;
	AssertBytesRemaining(numParams * 2 * sizeof(Value32));
	++mResult.mParamListSignatureCount;
	mResult.mParamSignatureCount += numParams;

	int32_t prevOffset = 0;
	for (size_t i = 0; i < numParams; ++i)
	{
		const int32_t offset = ReadValue32().mInt;
		if (offset >= prevOffset)
		{
			FunctionIsInvalid();
		}
		prevOffset = offset;

		ValidateSizeAndType();
	}
}
Exemple #6
0
void DisassemblerCore::DisassembleBlob()
{
	const size_t blobStart = GetPosition();
	const size_t blobSize = ReadValue32().mUInt;
	const size_t blobEnd = blobStart + blobSize;
	const size_t idIndex = ReadValue16().mUShort;

	if (idIndex == mValidationResult.mListBlobIdIndex)
	{
		DisassembleListBlob();
	}
	else if (idIndex == mValidationResult.mFunctionBlobIdIndex)
	{
		DisassembleFunctionBlob(blobEnd);
	}
	else if (idIndex == mValidationResult.mDataBlobIdIndex)
	{
		DisassembleDataBlob(blobEnd);
	}
	else
	{
		SetPosition(blobEnd);
	}
}
Exemple #7
0
void DisassemblerCore::DisassembleDataBlob(size_t blobEnd)
{
	const size_t nameIndex = ReadValue16().mUShort;

	mOutStream.Print("Data: ");
	const SignatureType type = DisassembleSizeAndType();
	mOutStream.Print(" ");
	mQualifiedNameTable[nameIndex].PrintTo(mOutStream);

	const Value32 payload = ReadValue32();

	switch (type)
	{
		case SIG_BOOL:
		{
			mOutStream.Print(" = %s\n", (payload.mInt == 0) ? "false" : "true");
		}
		break;

		case SIG_CHAR:
		case SIG_UCHAR:
		{
			mOutStream.Print(" = %c\n", payload.mInt);
		}
		break;

		case SIG_SHORT:
		case SIG_INT:
		{
			mOutStream.Print(" = %" BOND_PRId32 "\n", payload.mInt);
		}
		break;

		case SIG_USHORT:
		case SIG_UINT:
		{
			mOutStream.Print(" = %" BOND_PRIu32 "\n", payload.mUInt);
		}
		break;

		case SIG_LONG:
		{
			const int64_t value = IsInRange<uint16_t>(payload.mUInt) ? mValue64Table[payload.mUInt].mLong : 0;
			mOutStream.Print(" = %" BOND_PRId64 "\n", value);
		}
		break;

		case SIG_ULONG:
		{
			const uint64_t value = IsInRange<uint16_t>(payload.mUInt) ? mValue64Table[payload.mUInt].mULong : 0;
			mOutStream.Print(" = %" BOND_PRIu64 "\n", value);
		}
		break;

		case SIG_FLOAT:
		{
			mOutStream.Print(" = %f\n", payload.mFloat);
		}
		break;

		case SIG_DOUBLE:
		{
			const double value = IsInRange<uint16_t>(payload.mUInt) ? mValue64Table[payload.mUInt].mDouble : 0.0;
			mOutStream.Print(" = %f\n", value);
		}
		break;

		case SIG_VOID:
		case SIG_POINTER:
		case SIG_AGGREGATE:
		{
			mOutStream.Print("\n\talignment: %" BOND_PRIu32 "\n", payload.mUInt);
		}
		break;
	}

	// Disassemble the optional metadata blob.
	if (GetPosition() < blobEnd)
	{
		DisassembleBlob();
	}
}
Exemple #8
0
void DisassemblerCore::DisassembleFunctionBlob(size_t blobEnd)
{
	const size_t functionNameIndex = ReadValue16().mUShort;

	mOutStream.Print("Function: ");
	DisassembleSizeAndType();
	mOutStream.Print(" ");
	mQualifiedNameTable[functionNameIndex].PrintTo(mOutStream);
	mOutStream.Print("(");
	DisassembleParamListSignature();
	mOutStream.Print(")\n");

	const uint32_t argSize = ReadValue32().mUInt;
	const uint32_t packedArgSize = ReadValue32().mUInt;
	const uint32_t localSize = ReadValue32().mUInt;
	const uint32_t stackSize = ReadValue32().mUInt;
	const uint32_t framePointerAlignment = ReadValue32().mUInt;
	const uint32_t codeSize = ReadValue32().mUInt;
	const size_t codeStart = GetPosition();
	const size_t codeEnd = codeStart + codeSize;
	mOutStream.Print(
		"\targ size: %" BOND_PRIu32 "\n"
		"\tpacked arg size: %" BOND_PRIu32 "\n"
		"\tlocal size: %" BOND_PRIu32 "\n"
		"\tstack size: %" BOND_PRIu32 "\n"
		"\tframe pointer alignment: %" BOND_PRIu32 "\n"
		"\tcode size: %" BOND_PRIu32 "\n",
		argSize, packedArgSize, localSize, stackSize, framePointerAlignment, codeSize);

	while (GetPosition() < codeEnd)
	{
		const uint32_t opCodeAddress = uint32_t(GetPosition() - codeStart);
		const OpCode opCode = static_cast<OpCode>(mCboStream.Read());
		const OpCodeParam param = GetOpCodeParamType(opCode);

		mOutStream.Print("%6" BOND_PRIu32 ": %-12s", opCodeAddress, GetOpCodeMnemonic(opCode));

		switch (param)
		{
			case OC_PARAM_NONE:
				break;
			case OC_PARAM_CHAR:
				mOutStream.Print("%" BOND_PRId32, int32_t(int8_t(mCboStream.Read())));
				break;
			case OC_PARAM_UCHAR:
				mOutStream.Print("%" BOND_PRIu32, uint32_t(mCboStream.Read()));
				break;
			case OC_PARAM_UCHAR_CHAR:
				mOutStream.Print("%" BOND_PRIu32 ", %" BOND_PRId32, uint32_t(mCboStream.Read()), int32_t(int8_t(mCboStream.Read())));
				break;
			case OC_PARAM_SHORT:
				mOutStream.Print("%" BOND_PRId32, int32_t(ReadValue16().mShort));
				break;
			case OC_PARAM_USHORT:
				mOutStream.Print("%" BOND_PRId32, uint32_t(ReadValue16().mUShort));
				break;
			case OC_PARAM_INT:
			{
				const size_t valueIndex = ReadValue16().mUShort;
				const int32_t value = mValue32Table[valueIndex].mInt;
				mOutStream.Print("%" BOND_PRId32, value);
			}
			break;
			case OC_PARAM_VAL32:
			{
				const size_t valueIndex = ReadValue16().mUShort;
				const uint32_t value = mValue32Table[valueIndex].mUInt;
				mOutStream.Print("0x%" BOND_PRIx32, value);
			}
			break;
			case OC_PARAM_VAL64:
			{
				const size_t valueIndex = ReadValue16().mUShort;
				const uint64_t value = mValue64Table[valueIndex].mULong;
				mOutStream.Print("0x%" BOND_PRIx64, value);
			}
			break;
			case OC_PARAM_OFF16:
			{
				const int32_t offset = ReadValue16().mShort;
				const uint32_t baseAddress = uint32_t(GetPosition() - codeStart);
				mOutStream.Print("%" BOND_PRId32 " (%" BOND_PRIu32 ")", offset, baseAddress + offset);
			}
			break;
			case OC_PARAM_OFF32:
			{
				const size_t offsetIndex = ReadValue16().mUShort;
				const int32_t offset = mValue32Table[offsetIndex].mInt;
				const uint32_t baseAddress = uint32_t(GetPosition() - codeStart);
				mOutStream.Print("%" BOND_PRId32 " (%" BOND_PRIu32 ")", offset, baseAddress + offset);
			}
			break;
			case OC_PARAM_STRING:
			{
				const size_t stringIndex = ReadValue16().mUShort;
				WriteAbbreviatedString(mStringTable[stringIndex]);
			}
			break;
			case OC_PARAM_NAME:
			{
				const size_t nameIndex = ReadValue16().mUShort;
				mQualifiedNameTable[nameIndex].PrintTo(mOutStream);
			}
			break;
			case OC_PARAM_LOOKUPSWITCH:
			{
				Skip(AlignUpDelta(GetPosition() - codeStart, sizeof(Value32)));
				const int32_t defaultOffset = ReadValue32().mInt;
				const uint32_t numMatches = ReadValue32().mUInt;
				const size_t tableSize = numMatches * 2 * sizeof(Value32);
				const int32_t baseAddress = int32_t(GetPosition() + tableSize - codeStart);
				mOutStream.Print("\n%16s: %" BOND_PRId32 " (%" BOND_PRIu32 ")", "default", defaultOffset, baseAddress + defaultOffset);

				for (uint32_t i = 0; i < numMatches; ++i)
				{
					const int32_t match = ReadValue32().mInt;
					const int32_t offset = ReadValue32().mInt;
					mOutStream.Print("\n%16" BOND_PRId32 ": %" BOND_PRId32 " (%" BOND_PRIu32 ")", match, offset, baseAddress + offset);
				}
			}
			break;
			case OC_PARAM_TABLESWITCH:
			{
				Skip(AlignUpDelta(GetPosition() - codeStart, sizeof(Value32)));
				const int32_t defaultOffset = ReadValue32().mInt;
				const int32_t minMatch = ReadValue32().mInt;
				const int32_t maxMatch = ReadValue32().mInt;
				const uint32_t numMatches = maxMatch - minMatch + 1;
				const size_t tableSize = numMatches * sizeof(Value32);
				const int32_t baseAddress = int32_t(GetPosition() + tableSize - codeStart);
				mOutStream.Print("\n%16s: %" BOND_PRId32 " (%" BOND_PRIu32 ")", "default", defaultOffset, baseAddress + defaultOffset);

				for (uint32_t i = 0; i < numMatches; ++i)
				{
					const int32_t match = minMatch + i;
					const int32_t offset = ReadValue32().mInt;
					mOutStream.Print("\n%16" BOND_PRId32 ": %" BOND_PRId32 " (%" BOND_PRIu32 ")", match, offset, baseAddress + offset);
				}
			}
			break;
		}
		mOutStream.Print("\n");
	}

	// Disassemble the optional metadata blob.
	if (GetPosition() < blobEnd)
	{
		DisassembleBlob();
	}
}
static bool
ExtractProcInfoFromFde(const libunwindInfo* info, unw_word_t* addrp, unw_proc_info_t *pip, int need_unwind_info)
{
    unw_word_t addr = *addrp, fdeEndAddr, cieOffsetAddr, cieAddr;
    uint32_t value32;
    uint64_t value64;

    if (!ReadValue32(info, &addr, &value32)) {
        return false;
    }
    if (value32 != 0xffffffff)
    {
        int32_t cieOffset = 0;

        // In some configurations, an FDE with a 0 length indicates the end of the FDE-table
        if (value32 == 0) {
            return false;
        }
        // the FDE is in the 32-bit DWARF format */
        *addrp = fdeEndAddr = addr + value32;
        cieOffsetAddr = addr;

        if (!ReadValue32(info, &addr, (uint32_t*)&cieOffset)) {
            return false;
        }
        // Ignore CIEs (happens during linear search)
        if (cieOffset == 0) {
            return true;
        }
        // DWARF says that the CIE_pointer in the FDE is a .debug_frame-relative offset, 
        // but the GCC-generated .eh_frame sections instead store a "pcrelative" offset, 
        // which is just as fine as it's self-contained
        cieAddr = cieOffsetAddr - cieOffset;
    }
    else 
    {
        int64_t cieOffset = 0;

        // the FDE is in the 64-bit DWARF format */
        if (!ReadValue64(info, &addr, (uint64_t*)&value64)) {
            return false;
        }
        *addrp = fdeEndAddr = addr + value64;
        cieOffsetAddr = addr;

        if (!ReadValue64(info, &addr, (uint64_t*)&cieOffset)) {
            return false;
        }
        // Ignore CIEs (happens during linear search)
        if (cieOffset == 0) {
            return true;
        }
        // DWARF says that the CIE_pointer in the FDE is a .debug_frame-relative offset, 
        // but the GCC-generated .eh_frame sections instead store a "pcrelative" offset, 
        // which is just as fine as it's self-contained
        cieAddr = (unw_word_t)((uint64_t)cieOffsetAddr - cieOffset);
    }

    dwarf_cie_info_t dci;
    if (!ParseCie(info, cieAddr, &dci)) {
        return false;
    }

    unw_word_t ipStart, ipRange;
    if (!ReadEncodedPointer(info, &addr, dci.fde_encoding, UINTPTR_MAX, &ipStart)) {
        return false;
    }

    // IP-range has same encoding as FDE pointers, except that it's always an absolute value
    uint8_t ipRangeEncoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK;
    if (!ReadEncodedPointer(info, &addr, ipRangeEncoding, UINTPTR_MAX, &ipRange)) {
        return false;
    }
    pip->start_ip = ipStart;
    pip->end_ip = ipStart + ipRange;
    pip->handler = dci.handler;

    unw_word_t augmentationSize, augmentationEndAddr;
    if (dci.sized_augmentation) {
        if (!ReadULEB128(info, &addr, &augmentationSize)) {
            return false;
        }
        augmentationEndAddr = addr + augmentationSize;
    }

    // Read language specific data area address
    if (!ReadEncodedPointer(info, &addr, dci.lsda_encoding, pip->start_ip, &pip->lsda)) {
        return false;
    }

    // Now fill out the proc info if requested
    if (need_unwind_info)
    {
        if (dci.have_abi_marker)
        {
            if (!ReadValue16(info, &addr, &dci.abi)) {
                return false;
            }
            if (!ReadValue16(info, &addr, &dci.tag)) {
                return false;
            }
        }
        if (dci.sized_augmentation) {
            dci.fde_instr_start = augmentationEndAddr;
        }
        else {
            dci.fde_instr_start = addr;
        }
        dci.fde_instr_end = fdeEndAddr;

        pip->format = UNW_INFO_FORMAT_TABLE;
        pip->unwind_info_size = sizeof(dci);
        pip->unwind_info = malloc(sizeof(dci));
        if (pip->unwind_info == nullptr) {
            return -UNW_ENOMEM;
        }
        memcpy(pip->unwind_info, &dci, sizeof(dci));
    }

    return true;
}
Exemple #10
0
static bool 
ReadEncodedPointer(const libunwindInfo* info, unw_word_t* addr, unsigned char encoding, unw_word_t funcRel, unw_word_t* valp)
{
    unw_word_t initialAddr = *addr;
    uint16_t value16;
    uint32_t value32;
    uint64_t value64;
    unw_word_t value;

    if (encoding == DW_EH_PE_omit)
    {
        *valp = 0;
        return true;
    }
    else if (encoding == DW_EH_PE_aligned)
    {
        int size = sizeof(unw_word_t);
        *addr = (initialAddr + size - 1) & -size;
        return ReadPointer(info, addr, valp);
    }

    switch (encoding & DW_EH_PE_FORMAT_MASK)
    {
    case DW_EH_PE_ptr:
        if (!ReadPointer(info, addr, &value)) {
            return false;
        }
        break;

    case DW_EH_PE_uleb128:
        if (!ReadULEB128(info, addr, &value)) {
            return false;
        }
        break;

    case DW_EH_PE_sleb128:
        if (!ReadSLEB128(info, addr, &value)) {
            return false;
        }
        break;

    case DW_EH_PE_udata2:
        if (!ReadValue16(info, addr, &value16)) {
            return false;
        }
        value = value16;
        break;

    case DW_EH_PE_udata4:
        if (!ReadValue32(info, addr, &value32)) {
            return false;
        }
        value = value32;
        break;

    case DW_EH_PE_udata8:
        if (!ReadValue64(info, addr, &value64)) {
            return false;
        }
        value = value64;
        break;

    case DW_EH_PE_sdata2:
        if (!ReadValue16(info, addr, &value16)) {
            return false;
        }
        value = (int16_t)value16;
        break;

    case DW_EH_PE_sdata4:
        if (!ReadValue32(info, addr, &value32)) {
            return false;
        }
        value = (int32_t)value32;
        break;

    case DW_EH_PE_sdata8:
        if (!ReadValue64(info, addr, &value64)) {
            return false;
        }
        value = (int64_t)value64;
        break;

    default:
        ASSERT("ReadEncodedPointer: invalid encoding format %x\n", encoding);
        return false;
    }

    // 0 is a special value and always absolute
    if (value == 0) {
        *valp = 0;
        return true;
    }

    switch (encoding & DW_EH_PE_APPL_MASK)
    {
    case DW_EH_PE_absptr:
        break;

    case DW_EH_PE_pcrel:
        value += initialAddr;
        break;

    case DW_EH_PE_funcrel:
        _ASSERTE(funcRel != UINTPTR_MAX);
        value += funcRel;
        break;

    case DW_EH_PE_textrel:
    case DW_EH_PE_datarel:
    default:
        ASSERT("ReadEncodedPointer: invalid application type %x\n", encoding);
        return false;
    }

    if (encoding & DW_EH_PE_indirect)
    {
        unw_word_t indirect_addr = value;
        if (!ReadPointer(info, &indirect_addr, &value)) {
            return false;
        }
    }

    *valp = value;
    return true;
}
Exemple #11
0
CboValidator::Result CboValidatorCore::Validate()
{
	const uint32_t magicNumber = ReadValue32().mUInt;
	const uint32_t majorVersion = ReadValue16().mUShort;
	const uint32_t minorVersion = ReadValue16().mUShort;
	const uint16_t flags = ReadValue16().mUShort;
	const size_t tableStart = GetPosition();
	const size_t tableSize = ReadValue32().mUInt;
	const size_t value32Count = ReadValue16().mUShort;
	const size_t value64Count = ReadValue16().mUShort;
	const size_t stringCount = ReadValue16().mUShort;
	const size_t qualifiedNameCount = ReadValue16().mUShort;

	BOND_ASSERT_FORMAT(magicNumber == MAGIC_NUMBER, ("CBO file contains invalid magic number: 0x%" BOND_PRIx32 ".", magicNumber));
	BOND_ASSERT_FORMAT(IsCBOFormatLoadable(majorVersion, minorVersion), ("Unsupported CBO file format version: %" BOND_PRIu32 ".%" BOND_PRIu32 ". Only CBO file format versions in the range %" BOND_PRIu32 ".%" BOND_PRIu32 " through %" BOND_PRIu32 ".XX are supported.", majorVersion, minorVersion, CBO_MIN_SUPPORTED_MAJOR_VERSION, CBO_MIN_SUPPORTED_MINOR_VERSION, CBO_MAX_SUPPORTED_MAJOR_VERSION));

	mResult.mMajorVersion = majorVersion;
	mResult.mMinorVersion = minorVersion;
	mResult.mPointerSize = DecodePointerSize(flags);
	mResult.mValue32Count = value32Count;
	mResult.mValue64Count = value64Count;
	mResult.mStringCount = stringCount;
	mResult.mQualifiedNameCount = qualifiedNameCount;

	const size_t valueSize = (value32Count * sizeof(Value32)) + (value64Count * sizeof(Value64));
	AssertBytesRemaining(tableSize - (GetPosition() - tableStart));
	AssertBytesRemaining(valueSize);

	mValue32TableOffset = GetPosition();
	Skip((value32Count * sizeof(Value32)) + (value64Count * sizeof(Value64)));

	size_t stringByteCount = 0;
	for (size_t i = 0; i < stringCount; ++i)
	{
		AssertBytesRemaining(sizeof(Value16));
		const size_t stringLength = ReadValue16().mUShort;
		stringByteCount += stringLength;

		AssertBytesRemaining(stringLength);
		if (stringLength == BOND_BLOB_ID_LENGTH)
		{
			char str[BOND_BLOB_ID_LENGTH];
			mStream.Read(str, BOND_BLOB_ID_LENGTH);
			if (StringEqual(str, BOND_BLOB_ID_LENGTH, BOND_LIST_BLOB_ID, BOND_BLOB_ID_LENGTH))
			{
				mResult.mListBlobIdIndex = i;
			}
			else if (StringEqual(str, BOND_BLOB_ID_LENGTH, BOND_FUNCTION_BLOB_ID, BOND_BLOB_ID_LENGTH))
			{
				mResult.mFunctionBlobIdIndex = i;
			}
			else if (StringEqual(str, BOND_BLOB_ID_LENGTH, BOND_DATA_BLOB_ID, BOND_BLOB_ID_LENGTH))
			{
				mResult.mDataBlobIdIndex = i;
			}
		}
		else
		{
			mStream.AddOffset(Stream::pos_t(stringLength));
		}
	}
	mResult.mStringByteCount = stringByteCount;

	size_t qualifiedNameElementCount = 0;
	for (size_t i = 0; i < qualifiedNameCount; ++i)
	{
		AssertBytesRemaining(sizeof(Value16));
		const size_t numElements = ReadValue16().mUShort;
		AssertBytesRemaining(numElements * sizeof(Value16));
		qualifiedNameElementCount += numElements;

		if (numElements == 0)
		{
			mResult.mStaticInitializerNameIndex = i;
		}

		for (size_t j = 0; j < numElements; ++j)
		{
			const size_t elementIndex = ReadValue16().mUShort;
			if (elementIndex >= stringCount)
			{
				CboIsInvalid();
			}
		}
	}
	mResult.mQualifiedNameElementCount = qualifiedNameElementCount;

	const size_t tableEnd = tableStart + tableSize;
	if (GetPosition() != tableEnd)
	{
		CboIsInvalid();
		return mResult;
	}

	mResult.mDataAlignment = size_t(BOND_SLOT_SIZE);
	ValidateBlob();

	if (GetPosition() != mStreamEnd)
	{
		CboIsInvalid();
	}

	return mResult;
}
Exemple #12
0
void CboValidatorCore::ValidateFunctionBlob(size_t blobEnd)
{
	const size_t functionNameIndex = ValidateQualifiedNameIndex();
	ValidateSizeAndType();
	ValidateParamListSignature();

	AssertBytesRemaining(6 * sizeof(Value32));
	const uint32_t argSize = ReadValue32().mUInt;
	const uint32_t packedArgSize = ReadValue32().mUInt;
	const uint32_t localSize = ReadValue32().mUInt;
	Skip(sizeof(Value32)); // Ignore the stack size.
	const uint32_t framePointerAlignment = ReadValue32().mUInt;
	const size_t codeSize = ReadValue32().mUInt;

	if ((packedArgSize > argSize) ||
	    ((argSize % BOND_SLOT_SIZE) != 0) ||
	    ((packedArgSize % BOND_SLOT_SIZE) != 0) ||
	    ((localSize % BOND_SLOT_SIZE) != 0) ||
	    ((framePointerAlignment % BOND_SLOT_SIZE) != 0))
	{
		FunctionIsInvalid();
	}

	if (functionNameIndex == mResult.mStaticInitializerNameIndex)
	{
		++mResult.mStaticInitializerCount;
	}
	else
	{
		++mResult.mFunctionCount;
	}

	mResult.mCodeByteCount += AlignUp(codeSize, sizeof(Value32));
	AssertBytesRemaining(codeSize);
	const size_t codeStart = GetPosition();
	const size_t codeEnd = codeStart + codeSize;

	// Do a validation pass on the bytecode and ensure everything is converted to the correct endianness.
	while (GetPosition() < codeEnd)
	{
		const OpCode opCode = static_cast<OpCode>(mStream.Read());
		const OpCodeParam param = GetOpCodeParamType(opCode);

		switch (param)
		{
			case OC_PARAM_NONE:
				break;
			case OC_PARAM_CHAR:
			case OC_PARAM_UCHAR:
				AssertBytesRemaining(1);
				Skip(1);
				break;
			case OC_PARAM_UCHAR_CHAR:
			case OC_PARAM_SHORT:
			case OC_PARAM_USHORT:
				AssertBytesRemaining(sizeof(Value16));
				ReadValue16();
				break;
			case OC_PARAM_INT:
			case OC_PARAM_VAL32:
			{
				AssertBytesRemaining(sizeof(Value16));
				const size_t valueIndex = ReadValue16().mUShort;
				if (valueIndex >= mResult.mValue32Count)
				{
					CodeIsInvalid();
				}
			}
			break;
			case OC_PARAM_VAL64:
			{
				AssertBytesRemaining(sizeof(Value16));
				const size_t valueIndex = ReadValue16().mUShort;
				if (valueIndex >= mResult.mValue64Count)
				{
					CodeIsInvalid();
				}
			}
			break;
			case OC_PARAM_OFF16:
			{
				AssertBytesRemaining(sizeof(Value16));
				const int32_t offset = ReadValue16().mShort;
				const int32_t baseAddress = int32_t(GetPosition() - codeStart);
				const int32_t targetAddress = baseAddress + offset;
				if ((targetAddress < 0) || (uint32_t(targetAddress) > codeSize))
				{
					CodeIsInvalid();
				}
			}
			break;
			case OC_PARAM_OFF32:
			{
				AssertBytesRemaining(sizeof(Value16));
				const size_t offsetIndex = ReadValue16().mUShort;
				if (offsetIndex >= mResult.mValue32Count)
				{
					CodeIsInvalid();
				}
				else
				{
					const int32_t offset = ReadValue32TableAt(offsetIndex).mInt;
					const int32_t baseAddress = int32_t(GetPosition() - codeStart);
					const int32_t targetAddress = baseAddress + offset;
					if ((targetAddress < 0) || (uint32_t(targetAddress) > codeSize))
					{
						CodeIsInvalid();
					}
				}
			}
			break;
			case OC_PARAM_STRING:
			{
				AssertBytesRemaining(sizeof(Value16));
				const size_t stringIndex = ReadValue16().mUShort;
				if (stringIndex >= mResult.mStringCount)
				{
					CodeIsInvalid();
				}
			}
			break;
			case OC_PARAM_NAME:
			{
				AssertBytesRemaining(sizeof(Value16));
				const size_t nameIndex = ReadValue16().mUShort;
				if (nameIndex >= mResult.mQualifiedNameCount)
				{
					CodeIsInvalid();
				}
			}
			break;
			case OC_PARAM_LOOKUPSWITCH:
			{
				Skip(AlignUpDelta(GetPosition() - codeStart, sizeof(Value32)));
				AssertBytesRemaining(2 * sizeof(Value32));
				const int32_t defaultOffset = ReadValue32().mInt;
				const uint32_t numMatches = ReadValue32().mUInt;
				const size_t tableSize = numMatches * 2 * sizeof(Value32);
				const int32_t baseAddress = int32_t(GetPosition() + tableSize - codeStart);
				const int32_t defaultAddress = baseAddress + defaultOffset;

				AssertBytesRemaining(tableSize);
				if ((defaultAddress < 0) || (uint32_t(defaultAddress) > codeSize))
				{
					CodeIsInvalid();
				}

				for (uint32_t i = 0; i < numMatches; ++i)
				{
					// Skip the match.
					Skip(sizeof(Value32));
					const int32_t offset = ReadValue32().mInt;
					const int32_t targetAddress = baseAddress + offset;
					if ((targetAddress < 0) || (uint32_t(targetAddress) > codeSize))
					{
						CodeIsInvalid();
					}
				}
			}
			break;
			case OC_PARAM_TABLESWITCH:
			{
				Skip(AlignUpDelta(GetPosition() - codeStart, sizeof(Value32)));
				AssertBytesRemaining(3 * sizeof(Value32));
				const int32_t defaultOffset = ReadValue32().mInt;
				const int32_t minMatch = ReadValue32().mInt;
				const int32_t maxMatch = ReadValue32().mInt;
				const uint32_t numMatches = uint32_t(maxMatch - minMatch + 1);
				const size_t tableSize = numMatches * sizeof(Value32);
				const int32_t baseAddress = int32_t(GetPosition() + tableSize - codeStart);
				const int32_t defaultAddress = baseAddress + defaultOffset;

				AssertBytesRemaining(tableSize);
				if (minMatch > maxMatch)
				{
					CodeIsInvalid();
				}
				if ((defaultAddress < 0) || (uint32_t(defaultAddress) > codeSize))
				{
					CodeIsInvalid();
				}

				for (size_t i = 0; i < numMatches; ++i)
				{
					const int32_t offset = ReadValue32().mInt;
					const int32_t targetAddress = baseAddress + offset;
					if ((targetAddress < 0) || (uint32_t(targetAddress) > codeSize))
					{
						CodeIsInvalid();
					}
				}
			}
			break;
		}
	}

	// Validate the optional metadata blob.
	if (GetPosition() < blobEnd)
	{
		ValidateBlob();
	}
}