blob: 6660609165bad459a074cd93a40a77ae00fe5506 [file] [log] [blame]
// Copyright 2016 The Chromium OS 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 <sysexits.h>
#include <unistd.h>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <client/linux/minidump_writer/linux_core_dumper.h>
#include <client/linux/minidump_writer/minidump_writer.h>
#include "crash-reporter/core-collector/coredump_writer.h"
#include "crash-reporter/core-collector/logging.h"
namespace {
struct Flag {
std::string description;
std::string value;
};
using Flags = std::map<std::string, Flag>;
const char kCoreSwitch[] = "--coredump";
const char kDumpSwitch[] = "--minidump";
const char kHelpSwitch[] = "--help";
const char kPrefixSwitch[] = "--prefix";
const char kProcSwitch[] = "--proc";
void PrintUsage(const Flags& flags);
bool ParseFlags(int argc, char* argv[], Flags* flags);
} // namespace
const char* g_exec_name;
int main(int argc, char* argv[]) {
g_exec_name = argv[0];
Flags flags = {
{kCoreSwitch, {"Stripped core dump", "core"}},
{kDumpSwitch, {"Output minidump", "dump"}},
{kPrefixSwitch, {"Root directory to which .so paths are relative", ""}},
{kProcSwitch, {"Temporary directory for generated proc files", "/tmp"}},
};
if (argc == 2 && std::string(argv[1]) == kHelpSwitch) {
PrintUsage(flags);
return EX_OK;
}
if (!ParseFlags(argc, argv, &flags)) {
LOG_ERROR << "See '" << g_exec_name << ' ' << kHelpSwitch << "' for usage";
return EX_USAGE;
}
if (isatty(STDIN_FILENO)) {
LOG_ERROR << "Core dump must be piped to standard input";
return EX_USAGE;
}
const char *const core = flags.find(kCoreSwitch)->second.value.c_str(),
*const proc = flags.find(kProcSwitch)->second.value.c_str();
CoredumpWriter writer(STDIN_FILENO, core, proc);
const int error = writer.WriteCoredump();
if (error != EX_OK) {
LOG_ERROR << "Failed to write stripped core dump";
return error;
}
const char *const dump = flags.find(kDumpSwitch)->second.value.c_str(),
*const prefix =
flags.find(kPrefixSwitch)->second.value.c_str();
google_breakpad::MappingList mappings;
google_breakpad::AppMemoryList memory_list;
google_breakpad::LinuxCoreDumper dumper(/* unused */ -1, core, proc, prefix);
if (!WriteMinidump(dump, mappings, memory_list, &dumper)) {
LOG_ERROR << "Failed to convert core dump to minidump";
return EX_SOFTWARE;
}
return EX_OK;
}
namespace {
void PrintUsage(const Flags& flags) {
std::cout << "Generate minidump from core dump piped to standard input.\n"
<< std::endl;
for (const auto& flag : flags)
std::cout << std::setw(12) << flag.first << " " << flag.second.description
<< " (default: \"" << flag.second.value << "\")" << std::endl;
}
bool ParseFlags(int argc, char* argv[], Flags* flags) {
for (int i = 1; i < argc; ++i) {
const char* const flag = argv[i];
const auto it = flags->find(flag);
if (it == flags->end()) {
LOG_ERROR << "Invalid flag '" << flag << "'";
return false;
}
if (++i == argc) {
LOG_ERROR << "Missing value for flag '" << flag << "'";
return false;
}
it->second.value = argv[i];
}
return true;
}
} // namespace