blob: 2cdc3d069c89df512c0d10857feb021547fd4d18 [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 "encode.h"
#include <fuchsia/diagnostics/cpp/fidl.h>
#include <fuchsia/diagnostics/stream/cpp/fidl.h>
#include <lib/zx/clock.h>
#include <zircon/status.h>
#include <iostream>
#include <vector>
#include "fields.h"
namespace streams {
namespace {
const int WORD_SIZE = 8;
size_t padding_8byte(std::vector<uint8_t>* out) {
size_t length = out->size();
if (length % WORD_SIZE != 0) {
out->insert(out->end(), WORD_SIZE - length % WORD_SIZE, 0);
return WORD_SIZE - length % WORD_SIZE;
}
return 0;
}
size_t write_string(const std::string& str, std::vector<uint8_t>* out) {
out->insert(out->end(), std::begin(str), std::end(str));
size_t extra_padding = padding_8byte(out);
return (str.size() + extra_padding) / WORD_SIZE;
}
size_t write_signed_int(int64_t signed_int, std::vector<uint8_t>* out) {
size_t orig_length = out->size();
out->resize(out->size() + sizeof(int64_t));
auto* val_ptr = reinterpret_cast<int64_t*>(out->data() + orig_length);
*val_ptr = signed_int;
return sizeof(int64_t) / WORD_SIZE;
}
size_t write_unsigned_int(uint64_t unsigned_int, std::vector<uint8_t>* out) {
size_t orig_length = out->size();
out->resize(out->size() + sizeof(uint64_t));
auto* val_ptr = reinterpret_cast<uint64_t*>(out->data() + orig_length);
*val_ptr = unsigned_int;
return sizeof(uint64_t) / WORD_SIZE;
}
size_t write_float(double f, std::vector<uint8_t>* out) {
size_t orig_length = out->size();
out->resize(out->size() + sizeof(double));
auto* val_ptr = reinterpret_cast<double*>(out->data() + orig_length);
*val_ptr = f;
return sizeof(double) / WORD_SIZE;
}
size_t log_argument(const std::string& name, const fuchsia::diagnostics::stream::Value& value,
std::vector<uint8_t>* out) {
size_t header_idx = out->size();
out->resize(header_idx + WORD_SIZE); // WORD_SIZE=8 is for the header
size_t s_size = write_string(name, out);
size_t arg_size = s_size + 1; // 1 is for the header size
int type = 0;
uint64_t value_ref = 0;
switch (value.Which()) {
case fuchsia::diagnostics::stream::Value::Tag::kSignedInt:
type = 3;
arg_size += write_signed_int(value.signed_int(), out);
break;
case fuchsia::diagnostics::stream::Value::Tag::kUnsignedInt:
type = 4;
arg_size += write_unsigned_int(value.unsigned_int(), out);
break;
case fuchsia::diagnostics::stream::Value::Tag::kFloating:
type = 5;
arg_size += write_float(value.floating(), out);
break;
case fuchsia::diagnostics::stream::Value::Tag::kText:
type = 6;
arg_size += write_string(value.text(), out);
value_ref = value.text().length() > 0 ? (1 << 15) | value.text().length() : 0;
break;
case fuchsia::diagnostics::stream::Value::Tag::kUnknown:
break;
default:
break;
}
uint64_t header = ArgumentFields::Type::Make(type) | ArgumentFields::SizeWords::Make(arg_size) |
ArgumentFields::NameRefVal::Make(name.length()) |
ArgumentFields::NameRefMSB::Make(name.length() > 0 ? 1 : 0) |
ArgumentFields::ValueRef::Make(value_ref) | ArgumentFields::Reserved::Make(0);
std::memcpy(out->data() + header_idx, &header, WORD_SIZE);
return arg_size;
}
} // namespace
zx_status_t log_record(const fuchsia::diagnostics::stream::Record& record,
std::vector<uint8_t>* out) {
// Keep index to write header at the end
size_t idx = out->size();
out->resize(out->size() + WORD_SIZE); // WORD_SIZE=8 is header size in bytes
// Add timstamp
size_t time_index = out->size();
zx_time_t time = record.timestamp;
out->resize(out->size() + sizeof(time));
std::memcpy(out->data() + time_index, &time, sizeof(time));
// Add the arguments
size_t record_size = 2; // 2 words for Record Header
for (unsigned long i = 0; i < record.arguments.size(); i++) {
record_size += log_argument(record.arguments[i].name, record.arguments[i].value, out);
}
uint64_t header = HeaderFields::Type::Make(9) | HeaderFields::SizeWords::Make(record_size) |
HeaderFields::Reserved::Make(0) | HeaderFields::Severity::Make(record.severity);
// Set size and write header
std::memcpy(out->data() + idx, &header, WORD_SIZE);
return ZX_OK;
}
} // namespace streams