blob: 54c33da1d401771e99045d17511e6b92c4c8637e [file] [log] [blame]
// Copyright 2019 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 "tools/fidlcat/lib/inference.h"
#include <zircon/system/public/zircon/processargs.h>
#include <zircon/system/public/zircon/types.h>
#include <ios>
#include <ostream>
#include "src/lib/fidl_codec/printer.h"
#include "tools/fidlcat/lib/syscall_decoder.h"
namespace fidlcat {
// This is the first function which is intercepted. This gives us information about
// all the handles an application have at startup. However, for directory handles,
// we don't have the name of the directory.
void Inference::ExtractHandles(SyscallDecoder* decoder) {
constexpr int kNhandles = 0;
constexpr int kHandles = 1;
constexpr int kHandleInfo = 2;
// Get the values which have been harvest by the debugger using they argument number.
uint32_t nhandles = decoder->ArgumentValue(kNhandles);
const zx_handle_t* handles =
reinterpret_cast<const zx_handle_t*>(decoder->ArgumentContent(Stage::kEntry, kHandles));
const uint32_t* handle_info =
reinterpret_cast<const zx_handle_t*>(decoder->ArgumentContent(Stage::kEntry, kHandleInfo));
// Get the information about all the handles.
// The meaning of handle info is described in zircon/system/public/zircon/processargs.h
for (uint32_t handle = 0; handle < nhandles; ++handle) {
if (handles[handle] != 0) {
uint32_t type = PA_HND_TYPE(handle_info[handle]);
switch (type) {
case PA_FD:
AddHandleDescription(decoder->process_id(), handles[handle], "fd",
PA_HND_ARG(handle_info[handle]));
break;
case PA_DIRECTORY_REQUEST:
AddHandleDescription(decoder->process_id(), handles[handle], "directory-request", "/");
break;
default:
AddHandleDescription(decoder->process_id(), handles[handle], type);
break;
}
}
}
}
// This is the second function which is intercepted. This gives us information about
// all the handles which have not been used by processargs_extract_handles.
// This only adds information about directories.
void Inference::LibcExtensionsInit(SyscallDecoder* decoder) {
constexpr int kHandleCount = 0;
constexpr int kHandles = 1;
constexpr int kHandleInfo = 2;
constexpr int kNameCount = 3;
constexpr int kNames = 4;
// Get the values which have been harvest by the debugger using they argument number.
uint32_t handle_count = decoder->ArgumentValue(kHandleCount);
const zx_handle_t* handles =
reinterpret_cast<const zx_handle_t*>(decoder->ArgumentContent(Stage::kEntry, kHandles));
const uint32_t* handle_info =
reinterpret_cast<const zx_handle_t*>(decoder->ArgumentContent(Stage::kEntry, kHandleInfo));
uint32_t name_count = decoder->ArgumentValue(kNameCount);
const uint64_t* names =
reinterpret_cast<const uint64_t*>(decoder->ArgumentContent(Stage::kEntry, kNames));
// Get the information about the remaining handles.
// The meaning of handle info is described in zircon/system/public/zircon/processargs.h
for (uint32_t handle = 0; handle < handle_count; ++handle) {
if (handles[handle] != 0) {
uint32_t type = PA_HND_TYPE(handle_info[handle]);
switch (type) {
case PA_NS_DIR: {
uint32_t index = PA_HND_ARG(handle_info[handle]);
AddHandleDescription(decoder->process_id(), handles[handle], "dir",
(index < name_count)
? reinterpret_cast<const char*>(
decoder->BufferContent(Stage::kEntry, names[index]))
: "");
break;
}
case PA_FD:
AddHandleDescription(decoder->process_id(), handles[handle], "fd",
PA_HND_ARG(handle_info[handle]));
break;
case PA_DIRECTORY_REQUEST:
AddHandleDescription(decoder->process_id(), handles[handle], "directory-request", "/");
break;
default:
AddHandleDescription(decoder->process_id(), handles[handle], type);
break;
}
}
}
}
void Inference::InferMessage(SyscallDecoder* decoder,
fidl_codec::semantic::ContextType context_type) {
if (decoder->semantic() == nullptr) {
return;
}
constexpr int kHandle = 0;
zx_handle_t handle = decoder->ArgumentValue(kHandle);
if (handle != ZX_HANDLE_INVALID) {
fidl_codec::semantic::SemanticContext context(this, decoder->process_id(), handle, context_type,
decoder->decoded_request(),
decoder->decoded_response());
decoder->semantic()->ExecuteAssignments(&context);
}
}
void Inference::ZxChannelCreate(SyscallDecoder* decoder) {
constexpr int kOut0 = 1;
constexpr int kOut1 = 2;
zx_handle_t* out0 = reinterpret_cast<zx_handle_t*>(decoder->ArgumentContent(Stage::kExit, kOut0));
zx_handle_t* out1 = reinterpret_cast<zx_handle_t*>(decoder->ArgumentContent(Stage::kExit, kOut1));
if ((out0 != nullptr) && (*out0 != ZX_HANDLE_INVALID) && (out1 != nullptr) &&
(*out1 != ZX_HANDLE_INVALID)) {
// Provides the minimal semantic for both handles (that is they are channels).
AddHandleDescription(decoder->process_id(), *out0, "channel", next_channel_++);
AddHandleDescription(decoder->process_id(), *out1, "channel", next_channel_++);
// Links the two channels.
AddLinkedHandles(decoder->process_id(), *out0, *out1);
}
}
void Inference::ZxPortCreate(SyscallDecoder* decoder) {
constexpr int kOut = 1;
zx_handle_t* out = reinterpret_cast<zx_handle_t*>(decoder->ArgumentContent(Stage::kExit, kOut));
if ((out != nullptr) && (*out != ZX_HANDLE_INVALID)) {
// Provides the minimal semantic for the handle (that is it's a port).
AddHandleDescription(decoder->process_id(), *out, "port", next_port_++);
}
}
void Inference::ZxTimerCreate(SyscallDecoder* decoder) {
constexpr int kOut = 2;
zx_handle_t* out = reinterpret_cast<zx_handle_t*>(decoder->ArgumentContent(Stage::kExit, kOut));
if ((out != nullptr) && (*out != ZX_HANDLE_INVALID)) {
// Provides the minimal semantic for the handle (that is it's a timer).
AddHandleDescription(decoder->process_id(), *out, "timer", next_timer_++);
}
}
} // namespace fidlcat