Path: blob/main/contrib/llvm-project/lldb/source/Utility/DataExtractor.cpp
39587 views
//===-- DataExtractor.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Utility/DataExtractor.h"910#include "lldb/lldb-defines.h"11#include "lldb/lldb-enumerations.h"12#include "lldb/lldb-forward.h"13#include "lldb/lldb-types.h"1415#include "lldb/Utility/DataBuffer.h"16#include "lldb/Utility/DataBufferHeap.h"17#include "lldb/Utility/LLDBAssert.h"18#include "lldb/Utility/Log.h"19#include "lldb/Utility/Stream.h"20#include "lldb/Utility/StreamString.h"21#include "lldb/Utility/UUID.h"2223#include "llvm/ADT/ArrayRef.h"24#include "llvm/ADT/SmallVector.h"25#include "llvm/ADT/StringExtras.h"26#include "llvm/Support/LEB128.h"27#include "llvm/Support/MD5.h"28#include "llvm/Support/MathExtras.h"2930#include <algorithm>31#include <array>32#include <cassert>33#include <cstdint>34#include <string>3536#include <cctype>37#include <cinttypes>38#include <cstring>3940using namespace lldb;41using namespace lldb_private;4243static inline uint16_t ReadInt16(const unsigned char *ptr, offset_t offset) {44uint16_t value;45memcpy(&value, ptr + offset, 2);46return value;47}4849static inline uint32_t ReadInt32(const unsigned char *ptr,50offset_t offset = 0) {51uint32_t value;52memcpy(&value, ptr + offset, 4);53return value;54}5556static inline uint64_t ReadInt64(const unsigned char *ptr,57offset_t offset = 0) {58uint64_t value;59memcpy(&value, ptr + offset, 8);60return value;61}6263static inline uint16_t ReadInt16(const void *ptr) {64uint16_t value;65memcpy(&value, ptr, 2);66return value;67}6869static inline uint16_t ReadSwapInt16(const unsigned char *ptr,70offset_t offset) {71uint16_t value;72memcpy(&value, ptr + offset, 2);73return llvm::byteswap<uint16_t>(value);74}7576static inline uint32_t ReadSwapInt32(const unsigned char *ptr,77offset_t offset) {78uint32_t value;79memcpy(&value, ptr + offset, 4);80return llvm::byteswap<uint32_t>(value);81}8283static inline uint64_t ReadSwapInt64(const unsigned char *ptr,84offset_t offset) {85uint64_t value;86memcpy(&value, ptr + offset, 8);87return llvm::byteswap<uint64_t>(value);88}8990static inline uint16_t ReadSwapInt16(const void *ptr) {91uint16_t value;92memcpy(&value, ptr, 2);93return llvm::byteswap<uint16_t>(value);94}9596static inline uint32_t ReadSwapInt32(const void *ptr) {97uint32_t value;98memcpy(&value, ptr, 4);99return llvm::byteswap<uint32_t>(value);100}101102static inline uint64_t ReadSwapInt64(const void *ptr) {103uint64_t value;104memcpy(&value, ptr, 8);105return llvm::byteswap<uint64_t>(value);106}107108static inline uint64_t ReadMaxInt64(const uint8_t *data, size_t byte_size,109ByteOrder byte_order) {110uint64_t res = 0;111if (byte_order == eByteOrderBig)112for (size_t i = 0; i < byte_size; ++i)113res = (res << 8) | data[i];114else {115assert(byte_order == eByteOrderLittle);116for (size_t i = 0; i < byte_size; ++i)117res = (res << 8) | data[byte_size - 1 - i];118}119return res;120}121122DataExtractor::DataExtractor()123: m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)),124m_data_sp() {}125126// This constructor allows us to use data that is owned by someone else. The127// data must stay around as long as this object is valid.128DataExtractor::DataExtractor(const void *data, offset_t length,129ByteOrder endian, uint32_t addr_size,130uint32_t target_byte_size /*=1*/)131: m_start(const_cast<uint8_t *>(static_cast<const uint8_t *>(data))),132m_end(const_cast<uint8_t *>(static_cast<const uint8_t *>(data)) + length),133m_byte_order(endian), m_addr_size(addr_size), m_data_sp(),134m_target_byte_size(target_byte_size) {135assert(addr_size >= 1 && addr_size <= 8);136}137138// Make a shared pointer reference to the shared data in "data_sp" and set the139// endian swapping setting to "swap", and the address size to "addr_size". The140// shared data reference will ensure the data lives as long as any141// DataExtractor objects exist that have a reference to this data.142DataExtractor::DataExtractor(const DataBufferSP &data_sp, ByteOrder endian,143uint32_t addr_size,144uint32_t target_byte_size /*=1*/)145: m_byte_order(endian), m_addr_size(addr_size), m_data_sp(),146m_target_byte_size(target_byte_size) {147assert(addr_size >= 1 && addr_size <= 8);148SetData(data_sp);149}150151// Initialize this object with a subset of the data bytes in "data". If "data"152// contains shared data, then a reference to this shared data will added and153// the shared data will stay around as long as any object contains a reference154// to that data. The endian swap and address size settings are copied from155// "data".156DataExtractor::DataExtractor(const DataExtractor &data, offset_t offset,157offset_t length, uint32_t target_byte_size /*=1*/)158: m_byte_order(data.m_byte_order), m_addr_size(data.m_addr_size),159m_data_sp(), m_target_byte_size(target_byte_size) {160assert(m_addr_size >= 1 && m_addr_size <= 8);161if (data.ValidOffset(offset)) {162offset_t bytes_available = data.GetByteSize() - offset;163if (length > bytes_available)164length = bytes_available;165SetData(data, offset, length);166}167}168169DataExtractor::DataExtractor(const DataExtractor &rhs)170: m_start(rhs.m_start), m_end(rhs.m_end), m_byte_order(rhs.m_byte_order),171m_addr_size(rhs.m_addr_size), m_data_sp(rhs.m_data_sp),172m_target_byte_size(rhs.m_target_byte_size) {173assert(m_addr_size >= 1 && m_addr_size <= 8);174}175176// Assignment operator177const DataExtractor &DataExtractor::operator=(const DataExtractor &rhs) {178if (this != &rhs) {179m_start = rhs.m_start;180m_end = rhs.m_end;181m_byte_order = rhs.m_byte_order;182m_addr_size = rhs.m_addr_size;183m_data_sp = rhs.m_data_sp;184}185return *this;186}187188DataExtractor::~DataExtractor() = default;189190// Clears the object contents back to a default invalid state, and release any191// references to shared data that this object may contain.192void DataExtractor::Clear() {193m_start = nullptr;194m_end = nullptr;195m_byte_order = endian::InlHostByteOrder();196m_addr_size = sizeof(void *);197m_data_sp.reset();198}199200// If this object contains shared data, this function returns the offset into201// that shared data. Else zero is returned.202size_t DataExtractor::GetSharedDataOffset() const {203if (m_start != nullptr) {204const DataBuffer *data = m_data_sp.get();205if (data != nullptr) {206const uint8_t *data_bytes = data->GetBytes();207if (data_bytes != nullptr) {208assert(m_start >= data_bytes);209return m_start - data_bytes;210}211}212}213return 0;214}215216// Set the data with which this object will extract from to data starting at217// BYTES and set the length of the data to LENGTH bytes long. The data is218// externally owned must be around at least as long as this object points to219// the data. No copy of the data is made, this object just refers to this data220// and can extract from it. If this object refers to any shared data upon221// entry, the reference to that data will be released. Is SWAP is set to true,222// any data extracted will be endian swapped.223lldb::offset_t DataExtractor::SetData(const void *bytes, offset_t length,224ByteOrder endian) {225m_byte_order = endian;226m_data_sp.reset();227if (bytes == nullptr || length == 0) {228m_start = nullptr;229m_end = nullptr;230} else {231m_start = const_cast<uint8_t *>(static_cast<const uint8_t *>(bytes));232m_end = m_start + length;233}234return GetByteSize();235}236237// Assign the data for this object to be a subrange in "data" starting238// "data_offset" bytes into "data" and ending "data_length" bytes later. If239// "data_offset" is not a valid offset into "data", then this object will240// contain no bytes. If "data_offset" is within "data" yet "data_length" is too241// large, the length will be capped at the number of bytes remaining in "data".242// If "data" contains a shared pointer to other data, then a ref counted243// pointer to that data will be made in this object. If "data" doesn't contain244// a shared pointer to data, then the bytes referred to in "data" will need to245// exist at least as long as this object refers to those bytes. The address246// size and endian swap settings are copied from the current values in "data".247lldb::offset_t DataExtractor::SetData(const DataExtractor &data,248offset_t data_offset,249offset_t data_length) {250m_addr_size = data.m_addr_size;251assert(m_addr_size >= 1 && m_addr_size <= 8);252// If "data" contains shared pointer to data, then we can use that253if (data.m_data_sp) {254m_byte_order = data.m_byte_order;255return SetData(data.m_data_sp, data.GetSharedDataOffset() + data_offset,256data_length);257}258259// We have a DataExtractor object that just has a pointer to bytes260if (data.ValidOffset(data_offset)) {261if (data_length > data.GetByteSize() - data_offset)262data_length = data.GetByteSize() - data_offset;263return SetData(data.GetDataStart() + data_offset, data_length,264data.GetByteOrder());265}266return 0;267}268269// Assign the data for this object to be a subrange of the shared data in270// "data_sp" starting "data_offset" bytes into "data_sp" and ending271// "data_length" bytes later. If "data_offset" is not a valid offset into272// "data_sp", then this object will contain no bytes. If "data_offset" is273// within "data_sp" yet "data_length" is too large, the length will be capped274// at the number of bytes remaining in "data_sp". A ref counted pointer to the275// data in "data_sp" will be made in this object IF the number of bytes this276// object refers to in greater than zero (if at least one byte was available277// starting at "data_offset") to ensure the data stays around as long as it is278// needed. The address size and endian swap settings will remain unchanged from279// their current settings.280lldb::offset_t DataExtractor::SetData(const DataBufferSP &data_sp,281offset_t data_offset,282offset_t data_length) {283m_start = m_end = nullptr;284285if (data_length > 0) {286m_data_sp = data_sp;287if (data_sp) {288const size_t data_size = data_sp->GetByteSize();289if (data_offset < data_size) {290m_start = data_sp->GetBytes() + data_offset;291const size_t bytes_left = data_size - data_offset;292// Cap the length of we asked for too many293if (data_length <= bytes_left)294m_end = m_start + data_length; // We got all the bytes we wanted295else296m_end = m_start + bytes_left; // Not all the bytes requested were297// available in the shared data298}299}300}301302size_t new_size = GetByteSize();303304// Don't hold a shared pointer to the data buffer if we don't share any valid305// bytes in the shared buffer.306if (new_size == 0)307m_data_sp.reset();308309return new_size;310}311312// Extract a single unsigned char from the binary data and update the offset313// pointed to by "offset_ptr".314//315// RETURNS the byte that was extracted, or zero on failure.316uint8_t DataExtractor::GetU8(offset_t *offset_ptr) const {317const uint8_t *data = static_cast<const uint8_t *>(GetData(offset_ptr, 1));318if (data)319return *data;320return 0;321}322323// Extract "count" unsigned chars from the binary data and update the offset324// pointed to by "offset_ptr". The extracted data is copied into "dst".325//326// RETURNS the non-nullptr buffer pointer upon successful extraction of327// all the requested bytes, or nullptr when the data is not available in the328// buffer due to being out of bounds, or insufficient data.329void *DataExtractor::GetU8(offset_t *offset_ptr, void *dst,330uint32_t count) const {331const uint8_t *data =332static_cast<const uint8_t *>(GetData(offset_ptr, count));333if (data) {334// Copy the data into the buffer335memcpy(dst, data, count);336// Return a non-nullptr pointer to the converted data as an indicator of337// success338return dst;339}340return nullptr;341}342343// Extract a single uint16_t from the data and update the offset pointed to by344// "offset_ptr".345//346// RETURNS the uint16_t that was extracted, or zero on failure.347uint16_t DataExtractor::GetU16(offset_t *offset_ptr) const {348uint16_t val = 0;349const uint8_t *data =350static_cast<const uint8_t *>(GetData(offset_ptr, sizeof(val)));351if (data) {352if (m_byte_order != endian::InlHostByteOrder())353val = ReadSwapInt16(data);354else355val = ReadInt16(data);356}357return val;358}359360uint16_t DataExtractor::GetU16_unchecked(offset_t *offset_ptr) const {361uint16_t val;362if (m_byte_order == endian::InlHostByteOrder())363val = ReadInt16(m_start, *offset_ptr);364else365val = ReadSwapInt16(m_start, *offset_ptr);366*offset_ptr += sizeof(val);367return val;368}369370uint32_t DataExtractor::GetU32_unchecked(offset_t *offset_ptr) const {371uint32_t val;372if (m_byte_order == endian::InlHostByteOrder())373val = ReadInt32(m_start, *offset_ptr);374else375val = ReadSwapInt32(m_start, *offset_ptr);376*offset_ptr += sizeof(val);377return val;378}379380uint64_t DataExtractor::GetU64_unchecked(offset_t *offset_ptr) const {381uint64_t val;382if (m_byte_order == endian::InlHostByteOrder())383val = ReadInt64(m_start, *offset_ptr);384else385val = ReadSwapInt64(m_start, *offset_ptr);386*offset_ptr += sizeof(val);387return val;388}389390// Extract "count" uint16_t values from the binary data and update the offset391// pointed to by "offset_ptr". The extracted data is copied into "dst".392//393// RETURNS the non-nullptr buffer pointer upon successful extraction of394// all the requested bytes, or nullptr when the data is not available in the395// buffer due to being out of bounds, or insufficient data.396void *DataExtractor::GetU16(offset_t *offset_ptr, void *void_dst,397uint32_t count) const {398const size_t src_size = sizeof(uint16_t) * count;399const uint16_t *src =400static_cast<const uint16_t *>(GetData(offset_ptr, src_size));401if (src) {402if (m_byte_order != endian::InlHostByteOrder()) {403uint16_t *dst_pos = static_cast<uint16_t *>(void_dst);404uint16_t *dst_end = dst_pos + count;405const uint16_t *src_pos = src;406while (dst_pos < dst_end) {407*dst_pos = ReadSwapInt16(src_pos);408++dst_pos;409++src_pos;410}411} else {412memcpy(void_dst, src, src_size);413}414// Return a non-nullptr pointer to the converted data as an indicator of415// success416return void_dst;417}418return nullptr;419}420421// Extract a single uint32_t from the data and update the offset pointed to by422// "offset_ptr".423//424// RETURNS the uint32_t that was extracted, or zero on failure.425uint32_t DataExtractor::GetU32(offset_t *offset_ptr) const {426uint32_t val = 0;427const uint8_t *data =428static_cast<const uint8_t *>(GetData(offset_ptr, sizeof(val)));429if (data) {430if (m_byte_order != endian::InlHostByteOrder()) {431val = ReadSwapInt32(data);432} else {433memcpy(&val, data, 4);434}435}436return val;437}438439// Extract "count" uint32_t values from the binary data and update the offset440// pointed to by "offset_ptr". The extracted data is copied into "dst".441//442// RETURNS the non-nullptr buffer pointer upon successful extraction of443// all the requested bytes, or nullptr when the data is not available in the444// buffer due to being out of bounds, or insufficient data.445void *DataExtractor::GetU32(offset_t *offset_ptr, void *void_dst,446uint32_t count) const {447const size_t src_size = sizeof(uint32_t) * count;448const uint32_t *src =449static_cast<const uint32_t *>(GetData(offset_ptr, src_size));450if (src) {451if (m_byte_order != endian::InlHostByteOrder()) {452uint32_t *dst_pos = static_cast<uint32_t *>(void_dst);453uint32_t *dst_end = dst_pos + count;454const uint32_t *src_pos = src;455while (dst_pos < dst_end) {456*dst_pos = ReadSwapInt32(src_pos);457++dst_pos;458++src_pos;459}460} else {461memcpy(void_dst, src, src_size);462}463// Return a non-nullptr pointer to the converted data as an indicator of464// success465return void_dst;466}467return nullptr;468}469470// Extract a single uint64_t from the data and update the offset pointed to by471// "offset_ptr".472//473// RETURNS the uint64_t that was extracted, or zero on failure.474uint64_t DataExtractor::GetU64(offset_t *offset_ptr) const {475uint64_t val = 0;476const uint8_t *data =477static_cast<const uint8_t *>(GetData(offset_ptr, sizeof(val)));478if (data) {479if (m_byte_order != endian::InlHostByteOrder()) {480val = ReadSwapInt64(data);481} else {482memcpy(&val, data, 8);483}484}485return val;486}487488// GetU64489//490// Get multiple consecutive 64 bit values. Return true if the entire read491// succeeds and increment the offset pointed to by offset_ptr, else return492// false and leave the offset pointed to by offset_ptr unchanged.493void *DataExtractor::GetU64(offset_t *offset_ptr, void *void_dst,494uint32_t count) const {495const size_t src_size = sizeof(uint64_t) * count;496const uint64_t *src =497static_cast<const uint64_t *>(GetData(offset_ptr, src_size));498if (src) {499if (m_byte_order != endian::InlHostByteOrder()) {500uint64_t *dst_pos = static_cast<uint64_t *>(void_dst);501uint64_t *dst_end = dst_pos + count;502const uint64_t *src_pos = src;503while (dst_pos < dst_end) {504*dst_pos = ReadSwapInt64(src_pos);505++dst_pos;506++src_pos;507}508} else {509memcpy(void_dst, src, src_size);510}511// Return a non-nullptr pointer to the converted data as an indicator of512// success513return void_dst;514}515return nullptr;516}517518uint32_t DataExtractor::GetMaxU32(offset_t *offset_ptr,519size_t byte_size) const {520lldbassert(byte_size > 0 && byte_size <= 4 && "GetMaxU32 invalid byte_size!");521return GetMaxU64(offset_ptr, byte_size);522}523524uint64_t DataExtractor::GetMaxU64(offset_t *offset_ptr,525size_t byte_size) const {526lldbassert(byte_size > 0 && byte_size <= 8 && "GetMaxU64 invalid byte_size!");527switch (byte_size) {528case 1:529return GetU8(offset_ptr);530case 2:531return GetU16(offset_ptr);532case 4:533return GetU32(offset_ptr);534case 8:535return GetU64(offset_ptr);536default: {537// General case.538const uint8_t *data =539static_cast<const uint8_t *>(GetData(offset_ptr, byte_size));540if (data == nullptr)541return 0;542return ReadMaxInt64(data, byte_size, m_byte_order);543}544}545return 0;546}547548uint64_t DataExtractor::GetMaxU64_unchecked(offset_t *offset_ptr,549size_t byte_size) const {550switch (byte_size) {551case 1:552return GetU8_unchecked(offset_ptr);553case 2:554return GetU16_unchecked(offset_ptr);555case 4:556return GetU32_unchecked(offset_ptr);557case 8:558return GetU64_unchecked(offset_ptr);559default: {560uint64_t res = ReadMaxInt64(&m_start[*offset_ptr], byte_size, m_byte_order);561*offset_ptr += byte_size;562return res;563}564}565return 0;566}567568int64_t DataExtractor::GetMaxS64(offset_t *offset_ptr, size_t byte_size) const {569uint64_t u64 = GetMaxU64(offset_ptr, byte_size);570return llvm::SignExtend64(u64, 8 * byte_size);571}572573uint64_t DataExtractor::GetMaxU64Bitfield(offset_t *offset_ptr, size_t size,574uint32_t bitfield_bit_size,575uint32_t bitfield_bit_offset) const {576assert(bitfield_bit_size <= 64);577uint64_t uval64 = GetMaxU64(offset_ptr, size);578579if (bitfield_bit_size == 0)580return uval64;581582int32_t lsbcount = bitfield_bit_offset;583if (m_byte_order == eByteOrderBig)584lsbcount = size * 8 - bitfield_bit_offset - bitfield_bit_size;585586if (lsbcount > 0)587uval64 >>= lsbcount;588589uint64_t bitfield_mask =590(bitfield_bit_size == 64591? std::numeric_limits<uint64_t>::max()592: ((static_cast<uint64_t>(1) << bitfield_bit_size) - 1));593if (!bitfield_mask && bitfield_bit_offset == 0 && bitfield_bit_size == 64)594return uval64;595596uval64 &= bitfield_mask;597598return uval64;599}600601int64_t DataExtractor::GetMaxS64Bitfield(offset_t *offset_ptr, size_t size,602uint32_t bitfield_bit_size,603uint32_t bitfield_bit_offset) const {604assert(size >= 1 && "GetMaxS64Bitfield size must be >= 1");605assert(size <= 8 && "GetMaxS64Bitfield size must be <= 8");606int64_t sval64 = GetMaxS64(offset_ptr, size);607if (bitfield_bit_size == 0)608return sval64;609int32_t lsbcount = bitfield_bit_offset;610if (m_byte_order == eByteOrderBig)611lsbcount = size * 8 - bitfield_bit_offset - bitfield_bit_size;612if (lsbcount > 0)613sval64 >>= lsbcount;614uint64_t bitfield_mask = llvm::maskTrailingOnes<uint64_t>(bitfield_bit_size);615sval64 &= bitfield_mask;616// sign extend if needed617if (sval64 & ((static_cast<uint64_t>(1)) << (bitfield_bit_size - 1)))618sval64 |= ~bitfield_mask;619return sval64;620}621622float DataExtractor::GetFloat(offset_t *offset_ptr) const {623return Get<float>(offset_ptr, 0.0f);624}625626double DataExtractor::GetDouble(offset_t *offset_ptr) const {627return Get<double>(offset_ptr, 0.0);628}629630long double DataExtractor::GetLongDouble(offset_t *offset_ptr) const {631long double val = 0.0;632#if defined(__i386__) || defined(__amd64__) || defined(__x86_64__) || \633defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64)634*offset_ptr += CopyByteOrderedData(*offset_ptr, 10, &val, sizeof(val),635endian::InlHostByteOrder());636#else637*offset_ptr += CopyByteOrderedData(*offset_ptr, sizeof(val), &val,638sizeof(val), endian::InlHostByteOrder());639#endif640return val;641}642643// Extract a single address from the data and update the offset pointed to by644// "offset_ptr". The size of the extracted address comes from the645// "this->m_addr_size" member variable and should be set correctly prior to646// extracting any address values.647//648// RETURNS the address that was extracted, or zero on failure.649uint64_t DataExtractor::GetAddress(offset_t *offset_ptr) const {650assert(m_addr_size >= 1 && m_addr_size <= 8);651return GetMaxU64(offset_ptr, m_addr_size);652}653654uint64_t DataExtractor::GetAddress_unchecked(offset_t *offset_ptr) const {655assert(m_addr_size >= 1 && m_addr_size <= 8);656return GetMaxU64_unchecked(offset_ptr, m_addr_size);657}658659size_t DataExtractor::ExtractBytes(offset_t offset, offset_t length,660ByteOrder dst_byte_order, void *dst) const {661const uint8_t *src = PeekData(offset, length);662if (src) {663if (dst_byte_order != GetByteOrder()) {664// Validate that only a word- or register-sized dst is byte swapped665assert(length == 1 || length == 2 || length == 4 || length == 8 ||666length == 10 || length == 16 || length == 32);667668for (uint32_t i = 0; i < length; ++i)669(static_cast<uint8_t *>(dst))[i] = src[length - i - 1];670} else671::memcpy(dst, src, length);672return length;673}674return 0;675}676677// Extract data as it exists in target memory678lldb::offset_t DataExtractor::CopyData(offset_t offset, offset_t length,679void *dst) const {680const uint8_t *src = PeekData(offset, length);681if (src) {682::memcpy(dst, src, length);683return length;684}685return 0;686}687688// Extract data and swap if needed when doing the copy689lldb::offset_t690DataExtractor::CopyByteOrderedData(offset_t src_offset, offset_t src_len,691void *dst_void_ptr, offset_t dst_len,692ByteOrder dst_byte_order) const {693// Validate the source info694if (!ValidOffsetForDataOfSize(src_offset, src_len))695assert(ValidOffsetForDataOfSize(src_offset, src_len));696assert(src_len > 0);697assert(m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle);698699// Validate the destination info700assert(dst_void_ptr != nullptr);701assert(dst_len > 0);702assert(dst_byte_order == eByteOrderBig || dst_byte_order == eByteOrderLittle);703704// Validate that only a word- or register-sized dst is byte swapped705assert(dst_byte_order == m_byte_order || dst_len == 1 || dst_len == 2 ||706dst_len == 4 || dst_len == 8 || dst_len == 10 || dst_len == 16 ||707dst_len == 32);708709// Must have valid byte orders set in this object and for destination710if (!(dst_byte_order == eByteOrderBig ||711dst_byte_order == eByteOrderLittle) ||712!(m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle))713return 0;714715uint8_t *dst = static_cast<uint8_t *>(dst_void_ptr);716const uint8_t *src = PeekData(src_offset, src_len);717if (src) {718if (dst_len >= src_len) {719// We are copying the entire value from src into dst. Calculate how many,720// if any, zeroes we need for the most significant bytes if "dst_len" is721// greater than "src_len"...722const size_t num_zeroes = dst_len - src_len;723if (dst_byte_order == eByteOrderBig) {724// Big endian, so we lead with zeroes...725if (num_zeroes > 0)726::memset(dst, 0, num_zeroes);727// Then either copy or swap the rest728if (m_byte_order == eByteOrderBig) {729::memcpy(dst + num_zeroes, src, src_len);730} else {731for (uint32_t i = 0; i < src_len; ++i)732dst[i + num_zeroes] = src[src_len - 1 - i];733}734} else {735// Little endian destination, so we lead the value bytes736if (m_byte_order == eByteOrderBig) {737for (uint32_t i = 0; i < src_len; ++i)738dst[i] = src[src_len - 1 - i];739} else {740::memcpy(dst, src, src_len);741}742// And zero the rest...743if (num_zeroes > 0)744::memset(dst + src_len, 0, num_zeroes);745}746return src_len;747} else {748// We are only copying some of the value from src into dst..749750if (dst_byte_order == eByteOrderBig) {751// Big endian dst752if (m_byte_order == eByteOrderBig) {753// Big endian dst, with big endian src754::memcpy(dst, src + (src_len - dst_len), dst_len);755} else {756// Big endian dst, with little endian src757for (uint32_t i = 0; i < dst_len; ++i)758dst[i] = src[dst_len - 1 - i];759}760} else {761// Little endian dst762if (m_byte_order == eByteOrderBig) {763// Little endian dst, with big endian src764for (uint32_t i = 0; i < dst_len; ++i)765dst[i] = src[src_len - 1 - i];766} else {767// Little endian dst, with big endian src768::memcpy(dst, src, dst_len);769}770}771return dst_len;772}773}774return 0;775}776777// Extracts a variable length NULL terminated C string from the data at the778// offset pointed to by "offset_ptr". The "offset_ptr" will be updated with779// the offset of the byte that follows the NULL terminator byte.780//781// If the offset pointed to by "offset_ptr" is out of bounds, or if "length" is782// non-zero and there aren't enough available bytes, nullptr will be returned783// and "offset_ptr" will not be updated.784const char *DataExtractor::GetCStr(offset_t *offset_ptr) const {785const char *start = reinterpret_cast<const char *>(PeekData(*offset_ptr, 1));786// Already at the end of the data.787if (!start)788return nullptr;789790const char *end = reinterpret_cast<const char *>(m_end);791792// Check all bytes for a null terminator that terminates a C string.793const char *terminator_or_end = std::find(start, end, '\0');794795// We didn't find a null terminator, so return nullptr to indicate that there796// is no valid C string at that offset.797if (terminator_or_end == end)798return nullptr;799800// Update offset_ptr for the caller to point to the data behind the801// terminator (which is 1 byte long).802*offset_ptr += (terminator_or_end - start + 1UL);803return start;804}805806// Extracts a NULL terminated C string from the fixed length field of length807// "len" at the offset pointed to by "offset_ptr". The "offset_ptr" will be808// updated with the offset of the byte that follows the fixed length field.809//810// If the offset pointed to by "offset_ptr" is out of bounds, or if the offset811// plus the length of the field is out of bounds, or if the field does not812// contain a NULL terminator byte, nullptr will be returned and "offset_ptr"813// will not be updated.814const char *DataExtractor::GetCStr(offset_t *offset_ptr, offset_t len) const {815const char *cstr = reinterpret_cast<const char *>(PeekData(*offset_ptr, len));816if (cstr != nullptr) {817if (memchr(cstr, '\0', len) == nullptr) {818return nullptr;819}820*offset_ptr += len;821return cstr;822}823return nullptr;824}825826// Peeks at a string in the contained data. No verification is done to make827// sure the entire string lies within the bounds of this object's data, only828// "offset" is verified to be a valid offset.829//830// Returns a valid C string pointer if "offset" is a valid offset in this831// object's data, else nullptr is returned.832const char *DataExtractor::PeekCStr(offset_t offset) const {833return reinterpret_cast<const char *>(PeekData(offset, 1));834}835836// Extracts an unsigned LEB128 number from this object's data starting at the837// offset pointed to by "offset_ptr". The offset pointed to by "offset_ptr"838// will be updated with the offset of the byte following the last extracted839// byte.840//841// Returned the extracted integer value.842uint64_t DataExtractor::GetULEB128(offset_t *offset_ptr) const {843const uint8_t *src = PeekData(*offset_ptr, 1);844if (src == nullptr)845return 0;846847unsigned byte_count = 0;848uint64_t result = llvm::decodeULEB128(src, &byte_count, m_end);849*offset_ptr += byte_count;850return result;851}852853// Extracts an signed LEB128 number from this object's data starting at the854// offset pointed to by "offset_ptr". The offset pointed to by "offset_ptr"855// will be updated with the offset of the byte following the last extracted856// byte.857//858// Returned the extracted integer value.859int64_t DataExtractor::GetSLEB128(offset_t *offset_ptr) const {860const uint8_t *src = PeekData(*offset_ptr, 1);861if (src == nullptr)862return 0;863864unsigned byte_count = 0;865int64_t result = llvm::decodeSLEB128(src, &byte_count, m_end);866*offset_ptr += byte_count;867return result;868}869870// Skips a ULEB128 number (signed or unsigned) from this object's data starting871// at the offset pointed to by "offset_ptr". The offset pointed to by872// "offset_ptr" will be updated with the offset of the byte following the last873// extracted byte.874//875// Returns the number of bytes consumed during the extraction.876uint32_t DataExtractor::Skip_LEB128(offset_t *offset_ptr) const {877uint32_t bytes_consumed = 0;878const uint8_t *src = PeekData(*offset_ptr, 1);879if (src == nullptr)880return 0;881882const uint8_t *end = m_end;883884if (src < end) {885const uint8_t *src_pos = src;886while ((src_pos < end) && (*src_pos++ & 0x80))887++bytes_consumed;888*offset_ptr += src_pos - src;889}890return bytes_consumed;891}892893// Dumps bytes from this object's data to the stream "s" starting894// "start_offset" bytes into this data, and ending with the byte before895// "end_offset". "base_addr" will be added to the offset into the dumped data896// when showing the offset into the data in the output information.897// "num_per_line" objects of type "type" will be dumped with the option to898// override the format for each object with "type_format". "type_format" is a899// printf style formatting string. If "type_format" is nullptr, then an900// appropriate format string will be used for the supplied "type". If the901// stream "s" is nullptr, then the output will be send to Log().902lldb::offset_t DataExtractor::PutToLog(Log *log, offset_t start_offset,903offset_t length, uint64_t base_addr,904uint32_t num_per_line,905DataExtractor::Type type) const {906if (log == nullptr)907return start_offset;908909offset_t offset;910offset_t end_offset;911uint32_t count;912StreamString sstr;913for (offset = start_offset, end_offset = offset + length, count = 0;914ValidOffset(offset) && offset < end_offset; ++count) {915if ((count % num_per_line) == 0) {916// Print out any previous string917if (sstr.GetSize() > 0) {918log->PutString(sstr.GetString());919sstr.Clear();920}921// Reset string offset and fill the current line string with address:922if (base_addr != LLDB_INVALID_ADDRESS)923sstr.Printf("0x%8.8" PRIx64 ":",924static_cast<uint64_t>(base_addr + (offset - start_offset)));925}926927switch (type) {928case TypeUInt8:929sstr.Printf(" %2.2x", GetU8(&offset));930break;931case TypeChar: {932char ch = GetU8(&offset);933sstr.Printf(" %c", llvm::isPrint(ch) ? ch : ' ');934} break;935case TypeUInt16:936sstr.Printf(" %4.4x", GetU16(&offset));937break;938case TypeUInt32:939sstr.Printf(" %8.8x", GetU32(&offset));940break;941case TypeUInt64:942sstr.Printf(" %16.16" PRIx64, GetU64(&offset));943break;944case TypePointer:945sstr.Printf(" 0x%" PRIx64, GetAddress(&offset));946break;947case TypeULEB128:948sstr.Printf(" 0x%" PRIx64, GetULEB128(&offset));949break;950case TypeSLEB128:951sstr.Printf(" %" PRId64, GetSLEB128(&offset));952break;953}954}955956if (!sstr.Empty())957log->PutString(sstr.GetString());958959return offset; // Return the offset at which we ended up960}961962size_t DataExtractor::Copy(DataExtractor &dest_data) const {963if (m_data_sp) {964// we can pass along the SP to the data965dest_data.SetData(m_data_sp);966} else {967const uint8_t *base_ptr = m_start;968size_t data_size = GetByteSize();969dest_data.SetData(DataBufferSP(new DataBufferHeap(base_ptr, data_size)));970}971return GetByteSize();972}973974bool DataExtractor::Append(DataExtractor &rhs) {975if (rhs.GetByteOrder() != GetByteOrder())976return false;977978if (rhs.GetByteSize() == 0)979return true;980981if (GetByteSize() == 0)982return (rhs.Copy(*this) > 0);983984size_t bytes = GetByteSize() + rhs.GetByteSize();985986DataBufferHeap *buffer_heap_ptr = nullptr;987DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));988989if (!buffer_sp || buffer_heap_ptr == nullptr)990return false;991992uint8_t *bytes_ptr = buffer_heap_ptr->GetBytes();993994memcpy(bytes_ptr, GetDataStart(), GetByteSize());995memcpy(bytes_ptr + GetByteSize(), rhs.GetDataStart(), rhs.GetByteSize());996997SetData(buffer_sp);998999return true;1000}10011002bool DataExtractor::Append(void *buf, offset_t length) {1003if (buf == nullptr)1004return false;10051006if (length == 0)1007return true;10081009size_t bytes = GetByteSize() + length;10101011DataBufferHeap *buffer_heap_ptr = nullptr;1012DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));10131014if (!buffer_sp || buffer_heap_ptr == nullptr)1015return false;10161017uint8_t *bytes_ptr = buffer_heap_ptr->GetBytes();10181019if (GetByteSize() > 0)1020memcpy(bytes_ptr, GetDataStart(), GetByteSize());10211022memcpy(bytes_ptr + GetByteSize(), buf, length);10231024SetData(buffer_sp);10251026return true;1027}10281029void DataExtractor::Checksum(llvm::SmallVectorImpl<uint8_t> &dest,1030uint64_t max_data) {1031if (max_data == 0)1032max_data = GetByteSize();1033else1034max_data = std::min(max_data, GetByteSize());10351036llvm::MD5 md5;10371038const llvm::ArrayRef<uint8_t> data(GetDataStart(), max_data);1039md5.update(data);10401041llvm::MD5::MD5Result result;1042md5.final(result);10431044dest.clear();1045dest.append(result.begin(), result.end());1046}104710481049