blob: 3d2fea623ee35f2c918fca873e2d55ffd61e9847 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "garnet/bin/zxdb/expr/resolve_array.h"
#include "garnet/bin/zxdb/common/err.h"
#include "garnet/bin/zxdb/expr/expr_value.h"
#include "garnet/bin/zxdb/symbols/arch.h"
#include "garnet/bin/zxdb/symbols/array_type.h"
#include "garnet/bin/zxdb/symbols/modified_type.h"
#include "garnet/bin/zxdb/symbols/symbol_data_provider.h"
#include "garnet/bin/zxdb/symbols/type.h"
namespace zxdb {
namespace {
Err ResolveStaticArray(const ExprValue& array, const ArrayType* array_type,
size_t begin_index, size_t end_index,
std::vector<ExprValue>* result) {
const std::vector<uint8_t>& data = array.data();
if (data.size() < array_type->byte_size()) {
return Err(
"Array data (%zu bytes) is too small for the expected size "
"(%u bytes).",
data.size(), array_type->byte_size());
}
const Type* value_type = array_type->value_type();
uint32_t type_size = value_type->byte_size();
result->reserve(end_index - begin_index);
for (size_t i = begin_index; i < end_index; i++) {
size_t begin_offset = i * type_size;
if (begin_offset + type_size > data.size())
break;
std::vector<uint8_t> item_data(&data[begin_offset],
&data[begin_offset] + type_size);
result->emplace_back(fxl::RefPtr<Type>(const_cast<Type*>(value_type)),
std::move(item_data),
array.source().GetOffsetInto(begin_offset));
}
return Err();
}
// Handles the "Foo*" case.
void ResolvePointerArray(
fxl::RefPtr<SymbolDataProvider> data_provider, const ExprValue& array,
const ModifiedType* ptr_type, size_t begin_index, size_t end_index,
std::function<void(const Err&, std::vector<ExprValue>)> cb) {
const Type* value_type = ptr_type->modified().Get()->AsType();
if (!value_type) {
cb(Err("Bad type information."), std::vector<ExprValue>());
return;
}
value_type = value_type->GetConcreteType();
// The address is stored in the contents of the array value.
Err err = array.EnsureSizeIs(kTargetPointerSize);
if (err.has_error()) {
cb(err, std::vector<ExprValue>());
return;
}
TargetPointer base_address = array.GetAs<TargetPointer>();
uint32_t type_size = value_type->byte_size();
TargetPointer begin_address = base_address + type_size * begin_index;
TargetPointer end_address = base_address + type_size * end_index;
data_provider->GetMemoryAsync(begin_address, end_address - begin_address, [
type = fxl::RefPtr<Type>(const_cast<Type*>(value_type)), begin_address,
count = end_index - begin_index, cb = std::move(cb)
](const Err& err, std::vector<uint8_t> data) {
if (err.has_error()) {
cb(err, std::vector<ExprValue>());
return;
}
// Convert returned raw memory to ExprValues.
uint32_t type_size = type->byte_size();
std::vector<ExprValue> result;
result.reserve(count);
for (size_t i = 0; i < count; i++) {
size_t begin_offset = i * type_size;
if (begin_offset + type_size > data.size())
break; // Ran out of data, leave remaining results uninitialized.
std::vector<uint8_t> item_data(&data[begin_offset],
&data[begin_offset + type_size]);
result.emplace_back(type, std::move(item_data),
ExprValueSource(begin_address + begin_offset));
}
cb(Err(), std::move(result));
});
}
} // namespace
Err ResolveArray(const ExprValue& array, size_t begin_index, size_t end_index,
std::vector<ExprValue>* result) {
if (!array.type())
return Err("No type information.");
const Type* concrete = array.type()->GetConcreteType();
if (const ArrayType* array_type = concrete->AsArrayType()) {
return ResolveStaticArray(array, array_type, begin_index, end_index,
result);
}
return Err("Can't dereference a non-array type.");
}
void ResolveArray(fxl::RefPtr<SymbolDataProvider> data_provider,
const ExprValue& array, size_t begin_index, size_t end_index,
std::function<void(const Err&, std::vector<ExprValue>)> cb) {
if (!array.type()) {
cb(Err("No type information."), std::vector<ExprValue>());
return;
}
const Type* concrete = array.type()->GetConcreteType();
if (const ArrayType* array_type = concrete->AsArrayType()) {
std::vector<ExprValue> result;
Err err =
ResolveStaticArray(array, array_type, begin_index, end_index, &result);
cb(err, result);
return;
} else if (const ModifiedType* modified_type = concrete->AsModifiedType()) {
if (modified_type->tag() == Symbol::kTagPointerType) {
return ResolvePointerArray(data_provider, array, modified_type,
begin_index, end_index, std::move(cb));
}
}
cb(Err("Can't dereference a non-pointer or array type."),
std::vector<ExprValue>());
}
} // namespace zxdb