blob: 1744535799605cde0016099a806ad25df51dec34 [file] [log] [blame]
// Copyright 2017 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 <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <launchpad/launchpad.h>
#include <zircon/syscalls.h>
#include <fbl/algorithm.h>
#include "utils.h"
#if defined(__x86_64__) // entire file
constexpr char ipt_program[] = "/system/bin/ipt";
// Format string for dump output file prefix.
// PT dumps consist of several files, all beginning with this prefix.
constexpr char pt_path_prefix[] = "/tmp/crash-pt";
// The format of the path prefix, without the file suffix.
// The full name of dump files is $pt_path_prefix.num$seq.$suffix.
#define PT_PATH_FORMAT "%s.num%d"
// Test file suffix. This is the where PT buffer data is written.
// If $pt_path_prefix.$seq.$suffix doesn't exist then we use $seq.
constexpr char pt_file_test_suffix[] = "pt";
// Every dump is written to a new set of files:
// This counts to kMaxIptDumps and resets.
// When the max number of files has been written we don't write any more
// until at least one set of files has been deleted.
static int next_seq_num = 0;
constexpr int kMaxIptDumps = 4;
// Don't wait forever for ipt to run.
// It may take awhile to dump the data.
// This seems to be a good number.
constexpr zx_time_t run_timeout = ZX_SEC(10);
// Return the next sequence number to use or -1 if we've created the maximum
// number of dumps and can't make any more.
static int next_free_seq_num() {
char test_file[sizeof(pt_path_prefix) + 10 + sizeof(pt_file_test_suffix)];
for (int i = 0; i < kMaxIptDumps; ++i) {
int seq = (i + next_seq_num) % kMaxIptDumps;
snprintf(test_file, sizeof(test_file), PT_PATH_FORMAT ".%s",
pt_path_prefix, seq, pt_file_test_suffix);
if (access(test_file, F_OK) < 0)
return seq;
}
return -1;
}
static zx_status_t crashlogger_run(const char* name, int argc, const char* const* argv) {
launchpad_t *lp;
const char* executable = argv[0];
launchpad_create(ZX_HANDLE_INVALID, name, &lp);
launchpad_load_from_file(lp, executable);
launchpad_set_args(lp, argc, argv);
launchpad_clone(lp, LP_CLONE_ALL);
zx_handle_t child;
const char* errmsg;
zx_status_t status = launchpad_go(lp, &child, &errmsg);
if (status != ZX_OK)
return status;
zx_signals_t signals;
status = zx_object_wait_one(child, ZX_TASK_TERMINATED, zx_deadline_after(run_timeout),
&signals);
if (status != ZX_OK) {
// Leave reporting the error to the caller.
} else {
if (signals & ZX_TASK_TERMINATED) {
zx_info_process_t info;
status = zx_object_get_info(child, ZX_INFO_PROCESS, &info,
sizeof(info), nullptr, nullptr);
if (status == ZX_OK && info.exited) {
if (info.return_code != 0) {
// The child should have already printed its own error
// message, we just need to return some error code to the
// caller
status = ZX_ERR_IO;
}
} else {
// This shouldn't happen, but we don't want to kill crashlogger
// because of it. Return some indicative error code and let the
// caller report it.
status = ZX_ERR_BAD_STATE;
}
} else {
// This shouldn't happen, but we don't want to kill crashlogger
// because of it. Return some indicative error code and let the
// caller report it.
status = ZX_ERR_BAD_STATE;
}
}
zx_handle_close(child);
return status;
}
void try_dump_pt_data() {
printf("Hi, this is try_dump_pt_data\n");
if (access(ipt_program, F_OK) != 0) {
// We only get called if dumping ipt is enabled.
// Thus it's not noise to print a warning here.
printf("Unable to dump PT data, missing PT control program: %s\n", ipt_program);
return;
}
int seq_num = next_free_seq_num();
if (seq_num < 0) {
printf("Unable to dump IPT data, maximum number of dumps made.\n");
printf("To re-enable dumps, delete old ones by removing %s.*.\n",
pt_path_prefix);
return;
}
constexpr char output_path_prefix_arg[] = "--output-path-prefix=";
char full_output_path_prefix_arg[sizeof(output_path_prefix_arg) +
sizeof(pt_path_prefix) + 10/*seq#*/];
snprintf(full_output_path_prefix_arg, sizeof(full_output_path_prefix_arg),
"%s" PT_PATH_FORMAT, output_path_prefix_arg,
pt_path_prefix, seq_num);
const char* const argv_pt_dump[] = {
ipt_program,
full_output_path_prefix_arg,
"--verbose=2",
"--control",
"stop",
"dump",
"start",
};
zx_status_t status = crashlogger_run("ipt-dump",
fbl::count_of(argv_pt_dump), argv_pt_dump);
if (status == ZX_OK) {
printf("PT output written to " PT_PATH_FORMAT ".*\n",
pt_path_prefix, seq_num);
} else {
print_zx_error("Error dumping IPT data", status);
}
// TODO(dje): It may be useful to break up the actions.
// E.g., if the dump fails we still want to turn IPT back on.
}
#endif