206 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ValueMatcher.h"10#include "llvm/Support/Format.h"11#include "llvm/Support/InterleavedRange.h"12#include "llvm/Support/raw_os_ostream.h"13#include "llvm/Support/raw_ostream.h"14 15using namespace lldb_private;16 17static void FormatValueDetails(llvm::raw_ostream &os,18 Value::ValueType value_type,19 Value::ContextType context_type,20 const Scalar &scalar,21 llvm::ArrayRef<uint8_t> buffer_data) {22 os << "Value(";23 os << "value_type=" << Value::GetValueTypeAsCString(value_type);24 os << ", context_type=" << Value::GetContextTypeAsCString(context_type);25 26 if (value_type == Value::ValueType::HostAddress) {27 auto bytes_to_print = buffer_data.take_front(16);28 os << ", buffer=[";29 llvm::interleave(30 bytes_to_print,31 [&](uint8_t byte) {32 os << llvm::format("%02x", static_cast<unsigned>(byte));33 },34 [&]() { os << " "; });35 if (buffer_data.size() > 16)36 os << " ...";37 os << "] (" << buffer_data.size() << " bytes)";38 } else {39 os << ", value=" << scalar;40 }41 os << ")";42}43 44void lldb_private::PrintTo(const Value &val, std::ostream *os) {45 if (!os)46 return;47 48 llvm::raw_os_ostream raw_os(*os);49 FormatValueDetails(raw_os, val.GetValueType(), val.GetContextType(),50 val.GetScalar(), val.GetBuffer().GetData());51}52 53bool ValueMatcher::MatchAndExplain(const Value &val,54 std::ostream *stream) const {55 if (stream) {56 llvm::raw_os_ostream os(*stream);57 return MatchAndExplainImpl(val, os);58 }59 60 llvm::raw_null_ostream os;61 return MatchAndExplainImpl(val, os);62}63 64// Match the provided value and explain any mismatches using65// the raw_ostream. We use the llvm::raw_ostream here to simplify the formatting66// of Scalar values which already know how to print themselves to that stream.67bool ValueMatcher::MatchAndExplainImpl(const Value &val,68 llvm::raw_ostream &os) const {69 if (val.GetValueType() != m_value_type) {70 os << "value_type mismatch: expected "71 << Value::GetValueTypeAsCString(m_value_type) << ", got "72 << Value::GetValueTypeAsCString(val.GetValueType()) << " ";73 return false;74 }75 76 if (val.GetContextType() != m_context_type) {77 os << "context_type mismatch: expected "78 << Value::GetContextTypeAsCString(m_context_type) << ", got "79 << Value::GetContextTypeAsCString(val.GetContextType()) << " ";80 return false;81 }82 83 if (m_value_type == Value::ValueType::HostAddress) {84 const DataBufferHeap &buffer = val.GetBuffer();85 const size_t buffer_size = buffer.GetByteSize();86 if (buffer_size != m_expected_bytes.size()) {87 os << "buffer size mismatch: expected " << m_expected_bytes.size()88 << ", got " << buffer_size << " ";89 return false;90 }91 92 const uint8_t *data = buffer.GetBytes();93 for (size_t i = 0; i < buffer_size; ++i) {94 if (data[i] != m_expected_bytes[i]) {95 os << "byte mismatch at index " << i << ": expected "96 << llvm::format("0x%02x", static_cast<unsigned>(m_expected_bytes[i]))97 << ", got " << llvm::format("0x%02x", static_cast<unsigned>(data[i]))98 << " ";99 return false;100 }101 }102 } else {103 // For Scalar, FileAddress, and LoadAddress compare m_value.104 const Scalar &actual_scalar = val.GetScalar();105 if (actual_scalar != m_expected_scalar) {106 os << "scalar value mismatch: expected " << m_expected_scalar << ", got "107 << actual_scalar;108 return false;109 }110 }111 112 return true;113}114 115void ValueMatcher::DescribeTo(std::ostream *os) const {116 if (!os)117 return;118 llvm::raw_os_ostream raw_os(*os);119 FormatValueDetails(raw_os, m_value_type, m_context_type, m_expected_scalar,120 m_expected_bytes);121}122 123void ValueMatcher::DescribeNegationTo(std::ostream *os) const {124 if (!os)125 return;126 *os << "value does not match";127}128 129testing::Matcher<Value>130lldb_private::MatchScalarValue(Value::ValueType value_type,131 const Scalar &expected_scalar,132 Value::ContextType context_type) {133 return ValueMatcher(value_type, expected_scalar, context_type);134}135 136testing::Matcher<Value>137lldb_private::MatchHostValue(Value::ValueType value_type,138 const std::vector<uint8_t> &expected_bytes,139 Value::ContextType context_type) {140 return ValueMatcher(value_type, expected_bytes, context_type);141}142 143testing::Matcher<Value>144lldb_private::IsScalar(const Scalar &expected_scalar,145 Value::ContextType context_type) {146 return MatchScalarValue(Value::ValueType::Scalar, expected_scalar,147 context_type);148}149 150testing::Matcher<Value>151lldb_private::IsLoadAddress(const Scalar &expected_address,152 Value::ContextType context_type) {153 return MatchScalarValue(Value::ValueType::LoadAddress, expected_address,154 context_type);155}156 157testing::Matcher<Value>158lldb_private::IsFileAddress(const Scalar &expected_address,159 Value::ContextType context_type) {160 return MatchScalarValue(Value::ValueType::FileAddress, expected_address,161 context_type);162}163 164testing::Matcher<Value>165lldb_private::IsHostValue(const std::vector<uint8_t> &expected_bytes,166 Value::ContextType context_type) {167 return MatchHostValue(Value::ValueType::HostAddress, expected_bytes,168 context_type);169}170 171Scalar lldb_private::GetScalar(unsigned bits, uint64_t value, bool sign) {172 Scalar scalar(value);173 scalar.TruncOrExtendTo(bits, sign);174 return scalar;175}176 177llvm::detail::ValueMatchesPoly<testing::Matcher<Value>>178lldb_private::ExpectScalar(const Scalar &expected_scalar,179 Value::ContextType context_type) {180 return llvm::HasValue(IsScalar(expected_scalar, context_type));181}182 183llvm::detail::ValueMatchesPoly<testing::Matcher<Value>>184lldb_private::ExpectScalar(unsigned bits, uint64_t value, bool sign,185 Value::ContextType context_type) {186 return ExpectScalar(GetScalar(bits, value, sign), context_type);187}188 189llvm::detail::ValueMatchesPoly<testing::Matcher<Value>>190lldb_private::ExpectLoadAddress(const Scalar &expected_address,191 Value::ContextType context_type) {192 return llvm::HasValue(IsLoadAddress(expected_address, context_type));193}194 195llvm::detail::ValueMatchesPoly<testing::Matcher<Value>>196lldb_private::ExpectFileAddress(const Scalar &expected_address,197 Value::ContextType context_type) {198 return llvm::HasValue(IsFileAddress(expected_address, context_type));199}200 201llvm::detail::ValueMatchesPoly<testing::Matcher<Value>>202lldb_private::ExpectHostAddress(const std::vector<uint8_t> &expected_bytes,203 Value::ContextType context_type) {204 return llvm::HasValue(IsHostValue(expected_bytes, context_type));205}206