void CboValidatorCore::ValidateDataBlob(size_t blobEnd) { ++mResult.mDataCount; ValidateQualifiedNameIndex(); AssertBytesRemaining(2 * sizeof(Value32)); const uint32_t sizeAndType = ReadValue32().mUInt; uint32_t size; SignatureType type; DecodeSizeAndType(sizeAndType, size, type); const Value32 payload = ReadValue32(); size_t alignment = size_t(BOND_SLOT_SIZE); if (type == SIG_AGGREGATE) { alignment = Max(alignment, size_t(payload.mUInt)); } mResult.mDataSize = AlignUp(mResult.mDataSize, alignment); mResult.mDataSize += size; mResult.mDataAlignment = Max(mResult.mDataAlignment, alignment); // Validate the optional metadata blob. if (GetPosition() < blobEnd) { ValidateBlob(); } }
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(); } }
Value32 CboValidatorCore::ReadValue32TableAt(size_t index) { const auto pos = mStream.GetPosition(); mStream.SetPosition(Stream::pos_t(mValue32TableOffset + (index * sizeof(Value32)))); const Value32 value = ReadValue32(); mStream.SetPosition(pos); return value; }
void DisassemblerCore::DisassembleListBlob() { const size_t numBlobs = ReadValue32().mUInt; for (size_t i = 0; i < numBlobs; ++i) { DisassembleBlob(); } }
void CboValidatorCore::ValidateListBlob() { AssertBytesRemaining(sizeof(Value32)); const size_t numBlobs = ReadValue32().mUInt; for (size_t i = 0; i < numBlobs; ++i) { ValidateBlob(); } }
void CboValidatorCore::ValidateSizeAndType() { AssertBytesRemaining(sizeof(Value32)); const uint32_t sizeAndType = ReadValue32().mUInt; uint32_t size; SignatureType type; DecodeSizeAndType(sizeAndType, size, type); // TODO: Do some sanity checks. }
SignatureType DisassemblerCore::DisassembleSizeAndType() { const uint32_t sizeAndType = ReadValue32().mUInt; uint32_t size; SignatureType type; DecodeSizeAndType(sizeAndType, size, type); const char *str = GetBondTypeMnemonic(type); mOutStream.Print(str, size); return type; }
static bool ReadPointer(const libunwindInfo* info, unw_word_t* addr, unw_word_t* valp) { #ifdef BIT64 uint64_t val64; if (ReadValue64(info, addr, &val64)) { *valp = val64; return true; } #else uint32_t val32; if (ReadValue32(info, addr, &val32)) { *valp = val32; return true; } #endif return false; }
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(); }
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(); } }
static bool LookupTableEntry(const libunwindInfo* info, int32_t ip, unw_word_t tableAddr, size_t tableCount, table_entry* entry, bool* found) { size_t low, high, mid; unw_word_t addr; int32_t start_ip; *found = false; // do a binary search on table for (low = 0, high = tableCount; low < high;) { mid = (low + high) / 2; addr = tableAddr + (mid * sizeof(table_entry)); if (!ReadValue32(info, &addr, (uint32_t*)&start_ip)) { return false; } if (ip < start_ip) { high = mid; } else { low = mid + 1; } } if (high > 0) { addr = tableAddr + ((high - 1) * sizeof(table_entry)); // Assumes that the table_entry is two 32 bit values _ASSERTE(sizeof(*entry) == sizeof(uint64_t)); if (!ReadValue64(info, &addr, (uint64_t*)entry)) { return false; } *found = true; } return true; }
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); } }
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; }
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(); } }
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(); } }
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; }
static bool ParseCie(const libunwindInfo* info, unw_word_t addr, dwarf_cie_info_t* dci) { uint8_t ch, version, fdeEncoding, handlerEncoding; unw_word_t cieLength, cieEndAddr; uint32_t value32; uint64_t value64; memset(dci, 0, sizeof (*dci)); // Pick appropriate default for FDE-encoding. DWARF spec says // start-IP (initial_location) and the code-size (address_range) are // "address-unit sized constants". The `R' augmentation can be used // to override this, but by default, we pick an address-sized unit // for fde_encoding. #if BIT64 fdeEncoding = DW_EH_PE_udata8; #else fdeEncoding = DW_EH_PE_udata4; #endif dci->lsda_encoding = DW_EH_PE_omit; dci->handler = 0; if (!ReadValue32(info, &addr, &value32)) { return false; } if (value32 != 0xffffffff) { // The CIE is in the 32-bit DWARF format uint32_t cieId; // DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 const uint32_t expectedId = 0; cieLength = value32; cieEndAddr = addr + cieLength; if (!ReadValue32(info, &addr, &cieId)) { return false; } if (cieId != expectedId) { ASSERT("ParseCie: unexpected cie id %x\n", cieId); return false; } } else { // The CIE is in the 64-bit DWARF format uint64_t cieId; // DWARF says CIE id should be 0xffffffffffffffff, but in .eh_frame, it's 0 const uint64_t expectedId = 0; if (!ReadValue64(info, &addr, &value64)) { return false; } cieLength = value64; cieEndAddr = addr + cieLength; if (!ReadValue64(info, &addr, &cieId)) { return false; } if (cieId != expectedId) { ASSERT("ParseCie: unexpected cie id %lx\n", cieId); return false; } } dci->cie_instr_end = cieEndAddr; if (!ReadValue8(info, &addr, &version)) { return false; } if (version != 1 && version != DWARF_CIE_VERSION) { ASSERT("ParseCie: invalid cie version %x\n", version); return false; } // Read the augmentation string uint8_t augmentationString[8]; memset(augmentationString, 0, sizeof(augmentationString)); for (int i = 0; i < sizeof(augmentationString); i++) { if (!ReadValue8(info, &addr, &ch)) { return false; } if (ch == 0) { break; } augmentationString[i] = ch; } // Read the code and data alignment if (!ReadULEB128(info, &addr, &dci->code_align)) { return false; } if (!ReadSLEB128(info, &addr, &dci->data_align)) { return false; } // Read the return-address column either as a u8 or as a uleb128 if (version == 1) { if (!ReadValue8(info, &addr, &ch)) { return false; } dci->ret_addr_column = ch; } else { if (!ReadULEB128(info, &addr, &dci->ret_addr_column)) { return false; } } // Parse the augmentation string for (int i = 0; i < sizeof(augmentationString); i++) { bool done = false; unw_word_t augmentationSize; switch (augmentationString[i]) { case '\0': done = true; break; case 'z': dci->sized_augmentation = 1; if (!ReadULEB128(info, &addr, &augmentationSize)) { return false; } break; case 'L': // read the LSDA pointer-encoding format if (!ReadValue8(info, &addr, &ch)) { return false; } dci->lsda_encoding = ch; break; case 'R': // read the FDE pointer-encoding format if (!ReadValue8(info, &addr, &fdeEncoding)) { return false; } break; case 'P': // read the personality-routine pointer-encoding format if (!ReadValue8(info, &addr, &handlerEncoding)) { return false; } if (!ReadEncodedPointer(info, &addr, handlerEncoding, UINTPTR_MAX, &dci->handler)) { return false; } break; case 'S': // This is a signal frame dci->signal_frame = 1; // Temporarily set it to one so dwarf_parse_fde() knows that // it should fetch the actual ABI/TAG pair from the FDE. dci->have_abi_marker = 1; break; default: if (dci->sized_augmentation) { // If we have the size of the augmentation body, we can skip // over the parts that we don't understand, so we're OK done = true; break; } ASSERT("ParseCie: unexpected argumentation string '%s'\n", augmentationString[i]); return false; } if (done) { break; } } dci->fde_encoding = fdeEncoding; dci->cie_instr_start = addr; return true; }
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; }