blob: 71329b6066033af799e2fbef5d18bb4465352517 [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 "src/lib/fidl_codec/semantic.h"
#include <zircon/processargs.h>
#include <zircon/types.h>
#include <string>
#include "src/lib/fidl_codec/printer.h"
#include "src/lib/fidl_codec/wire_object.h"
namespace fidl_codec {
namespace semantic {
void ExpressionStringLiteral::Dump(std::ostream& os) const { os << '\'' << value_ << '\''; }
bool ExpressionStringLiteral::Execute(SemanticContext* context, ExpressionValue* result) const {
result->set_string(value_);
return true;
}
void ExpressionRequest::Dump(std::ostream& os) const { os << "request"; }
bool ExpressionRequest::Execute(SemanticContext* context, ExpressionValue* result) const {
if (context->request() == nullptr) {
return false;
}
result->set_value(nullptr, context->request());
return true;
}
void ExpressionHandle::Dump(std::ostream& os) const { os << "handle"; }
bool ExpressionHandle::Execute(SemanticContext* context, ExpressionValue* result) const {
result->set_handle(context->handle());
return true;
}
void ExpressionHandleDescription::Dump(std::ostream& os) const {
os << "HandleDescription(" << *type_ << ", " << *path_ << ')';
}
bool ExpressionHandleDescription::Execute(SemanticContext* context, ExpressionValue* result) const {
ExpressionValue type;
ExpressionValue path;
if (!type_->Execute(context, &type) || !path_->Execute(context, &path)) {
return false;
}
if ((type.kind() != ExpressionValue::kString) || (path.kind() != ExpressionValue::kString)) {
return false;
}
result->set_inferred_handle_info(type.string(), -1, path.string(), "");
return true;
}
void ExpressionFieldAccess::Dump(std::ostream& os) const { os << *expression_ << '.' << field_; }
bool ExpressionFieldAccess::Execute(SemanticContext* context, ExpressionValue* result) const {
ExpressionValue value;
if (!expression_->Execute(context, &value)) {
return false;
}
if (value.kind() == ExpressionValue::kValue) {
const StructValue* struct_value = value.value()->AsStructValue();
if (struct_value != nullptr) {
std::pair<const Type*, const Value*> field_value = struct_value->GetFieldValue(field_);
if (field_value.second == nullptr) {
return false;
}
const StringValue* string = field_value.second->AsStringValue();
if (string == nullptr) {
result->set_value(field_value.first, field_value.second);
} else {
result->set_string(string->string());
}
return true;
}
if (field_ == "size") {
const StringValue* string_value = value.value()->AsStringValue();
if (string_value != nullptr) {
result->set_integer(string_value->string().size());
return true;
}
const VectorValue* vector_value = value.value()->AsVectorValue();
if (vector_value != nullptr) {
result->set_integer(vector_value->values().size());
return true;
}
}
}
return false;
}
void ExpressionSlash::Dump(std::ostream& os) const { os << *left_ << " / " << *right_; }
bool ExpressionSlash::Execute(SemanticContext* context, ExpressionValue* result) const {
ExpressionValue left_value;
ExpressionValue right_value;
if (!left_->Execute(context, &left_value) || !right_->Execute(context, &right_value)) {
return false;
}
const InferredHandleInfo* inferred_handle_info = nullptr;
if (left_value.kind() == ExpressionValue::kInferredHandleInfo) {
inferred_handle_info = left_value.inferred_handle_info();
}
if (left_value.kind() == ExpressionValue::kHandle) {
inferred_handle_info =
context->handle_semantic()->GetInferredHandleInfo(context->pid(), left_value.handle());
}
if (inferred_handle_info == nullptr) {
return false;
}
if (right_value.kind() == ExpressionValue::kString) {
if (inferred_handle_info->path().empty()) {
result->set_inferred_handle_info(inferred_handle_info->type(), inferred_handle_info->fd(),
right_value.string(), inferred_handle_info->attributes());
return true;
}
if (right_value.string() == ".") {
result->set_inferred_handle_info(inferred_handle_info->type(), inferred_handle_info->fd(),
inferred_handle_info->path(),
inferred_handle_info->attributes());
return true;
}
std::string path(right_value.string());
if (path.find("./") == 0) {
path.erase(0, 2);
}
if (inferred_handle_info->path() == "/") {
result->set_inferred_handle_info(inferred_handle_info->type(), inferred_handle_info->fd(),
"/" + path, inferred_handle_info->attributes());
return true;
}
result->set_inferred_handle_info(inferred_handle_info->type(), inferred_handle_info->fd(),
inferred_handle_info->path() + "/" + path,
inferred_handle_info->attributes());
return true;
}
return false;
}
void ExpressionColon::Dump(std::ostream& os) const { os << *left_ << " : " << *right_; }
bool ExpressionColon::Execute(SemanticContext* context, ExpressionValue* result) const {
ExpressionValue left_value;
ExpressionValue right_value;
if (!left_->Execute(context, &left_value) || !right_->Execute(context, &right_value)) {
return false;
}
const InferredHandleInfo* inferred_handle_info = nullptr;
if (left_value.kind() == ExpressionValue::kInferredHandleInfo) {
inferred_handle_info = left_value.inferred_handle_info();
}
if (left_value.kind() == ExpressionValue::kHandle) {
inferred_handle_info =
context->handle_semantic()->GetInferredHandleInfo(context->pid(), left_value.handle());
}
if (inferred_handle_info == nullptr) {
return false;
}
if (right_value.kind() == ExpressionValue::kString) {
if (inferred_handle_info->attributes().empty()) {
result->set_inferred_handle_info(inferred_handle_info->type(), inferred_handle_info->fd(),
inferred_handle_info->path(), right_value.string());
return true;
}
result->set_inferred_handle_info(
inferred_handle_info->type(), inferred_handle_info->fd(), inferred_handle_info->path(),
inferred_handle_info->attributes() + ", " + std::string(right_value.string()));
return true;
}
return false;
}
void Assignment::Dump(std::ostream& os) const { os << *destination_ << " = " << *source_ << '\n'; }
void Assignment::Execute(AssignmentSemanticContext* context) const {
ExpressionValue destination_value;
ExpressionValue source_value;
if (!destination_->Execute(context, &destination_value) ||
!source_->Execute(context, &source_value)) {
return;
}
if (destination_value.value() == nullptr) {
return;
}
auto handle_value = destination_value.value()->AsHandleValue();
if (handle_value == nullptr) {
return;
}
zx_handle_t destination_handle = handle_value->handle().handle;
if (destination_handle == ZX_HANDLE_INVALID) {
return;
}
// Currently we only work on requests. If we also work on response, this would need to be
// modified.
switch (context->type()) {
case ContextType::kRead:
break;
case ContextType::kWrite:
case ContextType::kCall:
destination_handle =
context->handle_semantic()->GetLinkedHandle(context->pid(), destination_handle);
if (destination_handle == ZX_HANDLE_INVALID) {
return;
}
break;
}
const InferredHandleInfo* inferred_handle_info = source_value.inferred_handle_info();
if ((inferred_handle_info == nullptr) && (source_value.handle() != ZX_HANDLE_INVALID)) {
inferred_handle_info =
context->handle_semantic()->GetInferredHandleInfo(context->pid(), source_value.handle());
}
context->handle_semantic()->CreateHandleInfo(context->timestamp(), context->tid(),
destination_handle);
context->handle_semantic()->AddInferredHandleInfo(context->pid(), destination_handle,
inferred_handle_info);
}
void MethodSemantic::Dump(std::ostream& os) const {
for (const auto& assignment : assignments_) {
assignment->Dump(os);
}
}
void MethodSemantic::ExecuteAssignments(AssignmentSemanticContext* context) const {
for (const auto& assignment : assignments_) {
assignment->Execute(context);
}
}
void DisplayExpression::Dump(std::ostream& os) const {
if (!header_.empty()) {
os << " \"" << header_ << '"';
}
if (expression_ != nullptr) {
os << ' ';
expression_->Dump(os);
}
if (!footer_.empty()) {
os << " \"" << footer_ << '"';
}
}
void DisplayExpression::PrettyPrint(PrettyPrinter& printer, SemanticContext* context) {
if (!header_.empty()) {
printer << header_;
}
if (expression_ != nullptr) {
fidl_codec::semantic::ExpressionValue value;
expression_->Execute(context, &value);
value.UseLinkedHandle(context);
value.PrettyPrint(printer);
}
if (!footer_.empty()) {
printer << footer_;
}
}
void MethodDisplay::Dump(std::ostream& os) const {
for (const auto& input : inputs_) {
os << "input_field:";
input->Dump(os);
os << ";\n";
}
for (const auto& result : results_) {
os << "result:";
result->Dump(os);
os << ";\n";
}
}
std::string_view InferredHandleInfo::Convert(uint32_t type) {
switch (type) {
case PA_PROC_SELF:
return "proc-self";
case PA_THREAD_SELF:
return "thread-self";
case PA_JOB_DEFAULT:
return "job-default";
case PA_VMAR_ROOT:
return "vmar-root";
case PA_VMAR_LOADED:
return "initial-program-image-vmar";
case PA_LDSVC_LOADER:
return "ldsvc-loader";
case PA_VMO_VDSO:
return "vdso-vmo";
case PA_VMO_STACK:
return "stack-vmo";
case PA_VMO_EXECUTABLE:
return "executable-vmo";
case PA_VMO_BOOTDATA:
return "bootdata-vmo";
case PA_VMO_BOOTFS:
return "bootfs-vmo";
case PA_VMO_KERNEL_FILE:
return "kernel-file-vmo";
case PA_NS_DIR:
return "dir";
case PA_FD:
return "fd";
case PA_DIRECTORY_REQUEST:
return "directory-request";
case PA_RESOURCE:
return "resource";
case PA_USER0:
return "user0";
case PA_USER1:
return "user1";
case PA_USER2:
return "user2";
default:
return "";
}
}
void InferredHandleInfo::Display(PrettyPrinter& printer) const {
if (!type_.empty()) {
printer << Green << type_ << ResetColor;
if (fd_ != -1) {
printer << ':' << Blue << fd_ << ResetColor;
}
if (!path_.empty()) {
printer << ':' << Blue << path_ << ResetColor;
}
if (!attributes_.empty()) {
printer << " [" << Blue << attributes_ << ResetColor << ']';
}
}
}
void ExpressionValue::UseLinkedHandle(const SemanticContext* context) {
if (kind_ == kValue) {
auto handle_value = value_->AsHandleValue();
if (handle_value != nullptr) {
set_handle(handle_value->handle().handle);
}
}
if (kind_ == kHandle) {
if (handle_ != ZX_HANDLE_INVALID) {
zx_handle_t linked_handle =
context->handle_semantic()->GetLinkedHandle(context->pid(), handle_);
if (linked_handle != ZX_HANDLE_INVALID) {
handle_ = linked_handle;
}
}
}
}
void ExpressionValue::PrettyPrint(PrettyPrinter& printer) {
switch (kind_) {
case kUndefined:
break;
case kValue:
value_->PrettyPrint(value_type_, printer);
break;
case kHandle: {
zx_handle_disposition_t handle_disposition{.operation = fidl_codec::kNoHandleDisposition,
.handle = handle_,
.type = ZX_OBJ_TYPE_NONE,
.rights = ZX_RIGHT_NONE,
.result = ZX_OK};
printer.DisplayHandle(handle_disposition);
break;
}
case kInferredHandleInfo:
inferred_handle_info_->Display(printer);
break;
case kString:
printer << Red << '"' << string_ << '"' << ResetColor;
break;
case kInteger:
printer << Blue << integer_ << ResetColor;
break;
}
}
} // namespace semantic
} // namespace fidl_codec