blob: ff7c51249ab930bb4c536517f2cd716027121431 [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/developer/debug/zxdb/console/commands/verb_handle.h"
#include "src/developer/debug/zxdb/client/process.h"
#include "src/developer/debug/zxdb/client/target.h"
#include "src/developer/debug/zxdb/console/command.h"
#include "src/developer/debug/zxdb/console/command_utils.h"
#include "src/developer/debug/zxdb/console/console.h"
#include "src/developer/debug/zxdb/console/format_handle.h"
#include "src/developer/debug/zxdb/console/output_buffer.h"
#include "src/developer/debug/zxdb/console/verbs.h"
namespace zxdb {
namespace {
constexpr int kKoidSwitch = 1;
constexpr int kHexSwitch = 2;
enum class LookupType {
kHandle, // Search for the object with the given handle value.
kKoid // Search for the object with the given koid.
};
const char kHandleShortHelp[] = "handle[s]: Print handle list or details.";
const char kHandleHelp[] =
R"(handle[s] [-k] [-x] [ <expression> ]
With no arguments, prints all handles for the process.
If an expression or number is given, more detailed information for the given
handle value (the default) or koid (with the "-k" option) will be printed.
👉 See "help expressions" for how to write expressions.
In addition to open handles, this command will print VMO ("Virtual Memory
Object") information for mapped VMOs, even if there is no open handle to it.
These will be shown with "<none>" for the handle value. To view detailed
information about these objects, reference them by koid using the "-k" switch.
Options
-k
Look up the object by koid instead of handle value. This will only match
objects visible to the process, not arbitrary objects in the system.
-x
Print numbers as hexadecimal. Otherwise defaults to decimal.
Examples
handle
process 1 handles
Print all handles for the current/given process.
handle -x h
handle -x some_object->handle
Prints the information for the given handle.
handle -k 7256
Prints the informat for the object with koid 7256.
)";
void OnEvalComplete(fxl::RefPtr<EvalContext> eval_context, fxl::WeakPtr<Process> weak_process,
LookupType lookup, ErrOrValue value, bool hex) {
Console* console = Console::get();
if (!weak_process)
return console->Output(Err("Process exited while requesting handles."));
if (value.has_error())
return console->Output(value.err());
uint64_t lookup_value = 0;
if (Err err = value.value().PromoteTo64(&lookup_value); err.has_error())
return console->Output(err);
weak_process->LoadInfoHandleTable([lookup, lookup_value,
hex](ErrOr<std::vector<debug_ipc::InfoHandle>> handles) {
Console* console = Console::get();
if (handles.has_error())
return console->Output(handles.err());
switch (lookup) {
case LookupType::kHandle:
for (const auto& handle : handles.value()) {
if (handle.handle_value == lookup_value)
return console->Output(FormatHandle(handle, hex));
}
console->Output("No handle with value " + std::to_string(lookup_value) +
" in the process.");
break;
case LookupType::kKoid:
for (const auto& handle : handles.value()) {
if (handle.koid == lookup_value)
return console->Output(FormatHandle(handle, hex));
}
console->Output("No object with koid " + std::to_string(lookup_value) + " in the process.");
break;
}
});
}
Err RunVerbHandle(ConsoleContext* context, const Command& cmd) {
if (Err err = AssertRunningTarget(context, "handle", cmd.target()); err.has_error())
return err;
LookupType lookup = cmd.HasSwitch(kKoidSwitch) ? LookupType::kKoid : LookupType::kHandle;
bool hex = cmd.HasSwitch(kHexSwitch);
if (cmd.args().empty()) {
cmd.target()->GetProcess()->LoadInfoHandleTable(
[hex](ErrOr<std::vector<debug_ipc::InfoHandle>> handles) {
Console* console = Console::get();
if (handles.has_error())
return console->Output(handles.err());
// Sory by handle value, then koid (mapped VMOs can have no handle value).
auto handles_sorted = handles.take_value();
std::sort(handles_sorted.begin(), handles_sorted.end(),
[](const debug_ipc::InfoHandle& a, const debug_ipc::InfoHandle& b) {
return std::tie(a.handle_value, a.koid) < std::tie(b.handle_value, b.koid);
});
console->Output(FormatHandles(handles_sorted, hex));
});
} else {
// Evaluate the expression, then print just that handle.
fxl::RefPtr<EvalContext> eval_context = GetEvalContextForCommand(cmd);
return EvalCommandExpression(
cmd, "handle", eval_context, false, false,
[eval_context, weak_process = cmd.target()->GetProcess()->GetWeakPtr(), lookup,
hex](ErrOrValue value) {
OnEvalComplete(eval_context, weak_process, lookup, std::move(value), hex);
});
}
return Err();
}
} // namespace
VerbRecord GetHandleVerbRecord() {
VerbRecord handle(&RunVerbHandle, {"handle", "handles"}, kHandleShortHelp, kHandleHelp,
CommandGroup::kQuery);
handle.param_type = VerbRecord::kOneParam;
handle.switches.emplace_back(kKoidSwitch, false, "", 'k');
handle.switches.emplace_back(kHexSwitch, false, "", 'x');
return handle;
}
} // namespace zxdb