示例#1
0
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;
}
示例#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();
}
示例#3
0
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;
}
示例#4
0
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;
}
示例#5
0
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;
}
示例#6
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;
}