blob: 2ce7106553fee575be6a7428b71485c0afd28b0f [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 <getopt.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <zircon/process.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include <zircon/types.h>
#include <algorithm>
#include <cmath>
#include <vector>
#include <task-utils/get.h>
#include "handles-internal.h"
namespace {
zx_status_t get_handles(zx_handle_t process, std::vector<zx_info_handle_extended_t>* out) {
size_t avail = 32;
while (true) {
out->resize(avail);
auto size = avail * sizeof(zx_info_handle_extended_t);
size_t actual = 0;
auto status =
zx_object_get_info(process, ZX_INFO_HANDLE_TABLE, out->data(), size, &actual, &avail);
if (status != ZX_OK) {
return status;
}
if (actual < avail) {
avail += 8u;
continue;
}
out->resize(actual);
return ZX_OK;
}
}
void print_help(FILE* f) {
fprintf(f, "Usage: handles [options] <pid>\n");
fprintf(f, " Prints the handle table of a process.\n");
fprintf(f, "Options:\n");
fprintf(f, " -t|--task Only include process|thread|job in the output\n");
fprintf(f, " -v|--vmo Only include vmos in the output\n");
fprintf(f, " -p|--port Only include ports in the output\n");
fprintf(f, " -c|--channel Only include threads in the output\n");
fprintf(f, " -e|--event Only include events | eventpairs in the output\n");
fprintf(f, " -s|--socket Only include sockets in the output\n");
fprintf(f, " -r|--reverse Exclude objects specified in the filter\n");
fprintf(f, " -h|--help Display this message\n");
}
} // namespace
int main(int argc, char** argv) {
Filter filter = kAll;
bool reverse_filter = false;
while (true) {
static option options[] = {
{"task", no_argument, nullptr, 't'},
{"vmo", no_argument, nullptr, 'v'},
{"port", no_argument, nullptr, 'p'},
{"channel", no_argument, nullptr, 'c'},
{"event", no_argument, nullptr, 'e'},
{"socket", no_argument, nullptr, 's'},
{"reverse", no_argument, nullptr, 'r'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
int option_index = 0;
int c = getopt_long(argc, argv, "tvpcesrh", options, &option_index);
if (c < 0) {
break;
}
switch (c) {
case 't':
filter += kThread;
filter += kProcess;
filter += kJob;
break;
case 'v':
filter += kVmo;
break;
case 'p':
filter += kPort;
break;
case 'c':
filter += kChannel;
break;
case 'e':
filter += kEvent;
filter += kEventPair;
break;
case 's':
filter += kSocket;
break;
case 'r':
reverse_filter = true;
break;
case 'h':
default:
print_help(c == 'h' ? stdout : stderr);
return c == 'h' ? 0 : 1;
}
} // while
if ((filter != kAll) && reverse_filter) {
filter = ~filter;
}
if (argc == 1) {
print_help(stderr);
return 1;
}
zx_koid_t koid = 0;
if (optind < argc) {
char* end;
koid = strtoull(argv[optind], &end, 0);
if (koid == 0) {
fprintf(stderr, "handles: unrecognized extra arguments:");
while (optind < argc) {
fprintf(stderr, " %s", argv[optind++]);
}
fprintf(stderr, "\n");
print_help(stderr);
return 1;
}
}
zx_handle_t process;
zx_obj_type_t type;
auto status = get_task_by_koid(koid, &type, &process);
if (status != ZX_OK) {
fprintf(stderr, "handles: can't get process, error %d\n", status);
return 1;
}
if (type != ZX_OBJ_TYPE_PROCESS) {
zx_handle_close(process);
fprintf(stderr, "handles: koid %lu is not a process id\n", koid);
return 1;
}
std::vector<zx_info_handle_extended_t> handles;
status = get_handles(process, &handles);
if (status != ZX_OK) {
fprintf(stderr, "handles: syscall error %d\n", status);
return 1;
}
print_handles(stdout, handles, filter);
return 0;
}