blob: 4d72dca7a2b50b3b831b26a7fa6f60bbca6bedae [file] [log] [blame]
// Copyright 2020 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 "disk_inspector/disk_struct.h"
#include <iostream>
#include <regex>
#include <utility>
#include <fs/trace.h>
#include "disk_primitive.h"
namespace disk_inspector {
std::unique_ptr<DiskStruct> DiskStruct::Create(std::string name, uint64_t size) {
return std::unique_ptr<DiskStruct>(new DiskStruct(std::move(name), size));
}
// TODO(tianruichen): Optimize memory usage of a DiskStruct by storing only a single copy
// of each DiskObj in some sort of global mapping and have DiskStruct only contain references.
void DiskStruct::AddField(std::string key, FieldType type, uint64_t field_offset, uint64_t count,
std::unique_ptr<DiskStruct> disk_struct) {
ZX_DEBUG_ASSERT(fields_.find(key) == fields_.end());
FieldInfo info;
info.count = count;
info.offset = field_offset;
switch (type) {
case FieldType::kUint8: {
auto element = std::make_unique<Primitive<uint8_t>>("uint8_t");
info.element_size = element->GetSize();
info.element = std::move(element);
break;
}
case FieldType::kUint16: {
auto element = std::make_unique<Primitive<uint16_t>>("uint16_t");
info.element_size = element->GetSize();
info.element = std::move(element);
break;
}
case FieldType::kUint32: {
auto element = std::make_unique<Primitive<uint32_t>>("uint32_t");
info.element_size = element->GetSize();
info.element = std::move(element);
break;
}
case FieldType::kUint64: {
auto element = std::make_unique<Primitive<uint64_t>>("uint64_t");
info.element_size = element->GetSize();
info.element = std::move(element);
break;
}
case FieldType::kDiskStruct: {
ZX_DEBUG_ASSERT_MSG(disk_struct != nullptr,
"disk_struct must be set for kDiskStruct field type.");
info.element_size = disk_struct->GetSize();
info.element = std::move(disk_struct);
break;
}
default: {
FS_TRACE_ERROR("Field %s uses an unsupported type to be parsed by DiskStruct\n", key.c_str());
info.element_size = 0;
info.element = nullptr;
info.count = -1;
return;
}
}
fields_[key] = std::move(info);
field_list_.emplace_back(key);
}
zx_status_t DiskStruct::WriteField(void* position, std::vector<std::string> keys,
std::vector<uint64_t> indices, const std::string& value) {
ZX_DEBUG_ASSERT(!keys.empty());
ZX_DEBUG_ASSERT(!indices.empty());
std::string key = keys[0];
keys.erase(keys.begin());
int64_t index = indices[0];
indices.erase(indices.begin());
auto field = fields_.find(key);
if (field == fields_.end()) {
FS_TRACE_ERROR("Field name %s is not in struct.\n", key.c_str());
return ZX_ERR_INVALID_ARGS;
};
FieldInfo& info = field->second;
if (info.count < 0) {
FS_TRACE_ERROR("Cannot write to unparsable field %s.\n", key.c_str());
return ZX_ERR_INVALID_ARGS;
}
if (info.count == 0 && index != 0) {
FS_TRACE_ERROR("Index (%ld) for field %s should be 0.\n", index, key.c_str());
return ZX_ERR_INVALID_ARGS;
}
if (info.count > 0 && index >= info.count) {
FS_TRACE_ERROR("Field %s index %ld greater than number of elements %ld\n", key.c_str(), index,
info.count);
return ZX_ERR_INVALID_ARGS;
}
void* element_position =
reinterpret_cast<char*>(position) + info.offset + info.element_size * index;
DiskObj* element = info.element.get();
element->WriteField(element_position, keys, indices, value);
return ZX_OK;
}
std::string InsertTabAfterNewLine(const std::string& input) {
return std::regex_replace(input, std::regex("\n"), "\n\t");
}
std::string DiskStruct::ToString(void* position, const PrintOptions& options) {
std::ostringstream stream;
stream << "Name: " << name_ << "\n";
for (const auto& field_name : field_list_) {
const FieldInfo& info = fields_.find(field_name)->second;
if (info.count < 0) {
stream << "\t" << field_name << ": Not supported. Cannot parse.\n";
continue;
}
if (info.count == 0) {
void* element_position = reinterpret_cast<char*>(position) + info.offset;
stream << "\t" << field_name << ": "
<< InsertTabAfterNewLine(info.element->ToString(element_position, options)) << "\n";
continue;
}
if (info.count > 0) {
stream << "\t" << field_name << ":";
if (options.hide_array) {
stream << " " << info.element->GetTypeName() << "[" << info.count << "] = { ... }\n";
} else {
stream << "\n";
for (uint32_t i = 0; i < info.count; ++i) {
void* element_position =
reinterpret_cast<char*>(position) + info.offset + i * info.element_size;
stream << "\t\t" << info.element->GetTypeName() + " #" << i << ": "
<< InsertTabAfterNewLine(info.element->ToString(element_position, options))
<< "\n";
}
}
}
}
return stream.str();
}
} // namespace disk_inspector