minidump-2-core: add an -o flag for controlling core output
Always writing to stdout makes it hard to debug, and hard to use in some script environments. Add an explicit -o flag to make it easier. BUG=chromium:598947 Change-Id: I79667d033c8bdc8412d3a44fe3557d65f704968f Reviewed-on: https://chromium-review.googlesource.com/403988 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
ed7dcced19
commit
54b524be13
1 changed files with 46 additions and 24 deletions
|
@ -99,6 +99,7 @@ static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1);
|
|||
struct Options {
|
||||
string minidump_path;
|
||||
bool verbose;
|
||||
int out_fd;
|
||||
string so_basedir;
|
||||
};
|
||||
|
||||
|
@ -111,6 +112,7 @@ Usage(int argc, const char* argv[]) {
|
|||
"\n"
|
||||
"Options:\n"
|
||||
" -v Enable verbose output\n"
|
||||
" -o <file> Write coredump to specified file (otherwise use stdout).\n"
|
||||
" -S <dir> Set soname base directory. This will force all debug/symbol\n"
|
||||
" lookups to be done in this directory rather than the filesystem\n"
|
||||
" layout as it exists in the crashing image. This path should end\n"
|
||||
|
@ -122,11 +124,12 @@ static void
|
|||
SetupOptions(int argc, const char* argv[], Options* options) {
|
||||
extern int optind;
|
||||
int ch;
|
||||
const char* output_file = NULL;
|
||||
|
||||
// Initialize the options struct as needed.
|
||||
options->verbose = false;
|
||||
|
||||
while ((ch = getopt(argc, (char * const *)argv, "hS:v")) != -1) {
|
||||
while ((ch = getopt(argc, (char * const *)argv, "ho:S:v")) != -1) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
Usage(argc, argv);
|
||||
|
@ -137,6 +140,9 @@ SetupOptions(int argc, const char* argv[], Options* options) {
|
|||
exit(1);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
output_file = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
options->so_basedir = optarg;
|
||||
break;
|
||||
|
@ -152,6 +158,17 @@ SetupOptions(int argc, const char* argv[], Options* options) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (output_file == NULL || !strcmp(output_file, "-")) {
|
||||
options->out_fd = STDOUT_FILENO;
|
||||
} else {
|
||||
options->out_fd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (options->out_fd == -1) {
|
||||
fprintf(stderr, "%s: could not open output %s: %s\n", argv[0],
|
||||
output_file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
options->minidump_path = argv[optind];
|
||||
}
|
||||
|
||||
|
@ -857,7 +874,8 @@ ParseExceptionStream(const Options& options, CrashedProcess* crashinfo,
|
|||
}
|
||||
|
||||
static bool
|
||||
WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
|
||||
WriteThread(const Options& options, const CrashedProcess::Thread& thread,
|
||||
int fatal_signal) {
|
||||
struct prstatus pr;
|
||||
memset(&pr, 0, sizeof(pr));
|
||||
|
||||
|
@ -875,18 +893,18 @@ WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
|
|||
nhdr.n_namesz = 5;
|
||||
nhdr.n_descsz = sizeof(struct prstatus);
|
||||
nhdr.n_type = NT_PRSTATUS;
|
||||
if (!writea(1, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(1, "CORE\0\0\0\0", 8) ||
|
||||
!writea(1, &pr, sizeof(struct prstatus))) {
|
||||
if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(options.out_fd, "CORE\0\0\0\0", 8) ||
|
||||
!writea(options.out_fd, &pr, sizeof(struct prstatus))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
nhdr.n_descsz = sizeof(user_fpregs_struct);
|
||||
nhdr.n_type = NT_FPREGSET;
|
||||
if (!writea(1, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(1, "CORE\0\0\0\0", 8) ||
|
||||
!writea(1, &thread.fpregs, sizeof(user_fpregs_struct))) {
|
||||
if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(options.out_fd, "CORE\0\0\0\0", 8) ||
|
||||
!writea(options.out_fd, &thread.fpregs, sizeof(user_fpregs_struct))) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -894,9 +912,9 @@ WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
|
|||
#if defined(__i386__)
|
||||
nhdr.n_descsz = sizeof(user_fpxregs_struct);
|
||||
nhdr.n_type = NT_PRXFPREG;
|
||||
if (!writea(1, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(1, "LINUX\0\0\0", 8) ||
|
||||
!writea(1, &thread.fpxregs, sizeof(user_fpxregs_struct))) {
|
||||
if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(options.out_fd, "LINUX\0\0\0", 8) ||
|
||||
!writea(options.out_fd, &thread.fpxregs, sizeof(user_fpxregs_struct))) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -1214,7 +1232,7 @@ main(int argc, const char* argv[]) {
|
|||
ehdr.e_phnum = 1 + // PT_NOTE
|
||||
crashinfo.mappings.size(); // memory mappings
|
||||
ehdr.e_shentsize= sizeof(Shdr);
|
||||
if (!writea(1, &ehdr, sizeof(Ehdr)))
|
||||
if (!writea(options.out_fd, &ehdr, sizeof(Ehdr)))
|
||||
return 1;
|
||||
|
||||
size_t offset = sizeof(Ehdr) + ehdr.e_phnum * sizeof(Phdr);
|
||||
|
@ -1236,7 +1254,7 @@ main(int argc, const char* argv[]) {
|
|||
phdr.p_type = PT_NOTE;
|
||||
phdr.p_offset = offset;
|
||||
phdr.p_filesz = filesz;
|
||||
if (!writea(1, &phdr, sizeof(phdr)))
|
||||
if (!writea(options.out_fd, &phdr, sizeof(phdr)))
|
||||
return 1;
|
||||
|
||||
phdr.p_type = PT_LOAD;
|
||||
|
@ -1269,7 +1287,7 @@ main(int argc, const char* argv[]) {
|
|||
phdr.p_filesz = 0;
|
||||
phdr.p_offset = 0;
|
||||
}
|
||||
if (!writea(1, &phdr, sizeof(phdr)))
|
||||
if (!writea(options.out_fd, &phdr, sizeof(phdr)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1278,36 +1296,36 @@ main(int argc, const char* argv[]) {
|
|||
nhdr.n_namesz = 5;
|
||||
nhdr.n_descsz = sizeof(prpsinfo);
|
||||
nhdr.n_type = NT_PRPSINFO;
|
||||
if (!writea(1, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(1, "CORE\0\0\0\0", 8) ||
|
||||
!writea(1, &crashinfo.prps, sizeof(prpsinfo))) {
|
||||
if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(options.out_fd, "CORE\0\0\0\0", 8) ||
|
||||
!writea(options.out_fd, &crashinfo.prps, sizeof(prpsinfo))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
nhdr.n_descsz = crashinfo.auxv_length;
|
||||
nhdr.n_type = NT_AUXV;
|
||||
if (!writea(1, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(1, "CORE\0\0\0\0", 8) ||
|
||||
!writea(1, crashinfo.auxv, crashinfo.auxv_length)) {
|
||||
if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
|
||||
!writea(options.out_fd, "CORE\0\0\0\0", 8) ||
|
||||
!writea(options.out_fd, crashinfo.auxv, crashinfo.auxv_length)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
|
||||
if (crashinfo.threads[i].tid == crashinfo.crashing_tid) {
|
||||
WriteThread(crashinfo.threads[i], crashinfo.fatal_signal);
|
||||
WriteThread(options, crashinfo.threads[i], crashinfo.fatal_signal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
|
||||
if (crashinfo.threads[i].tid != crashinfo.crashing_tid)
|
||||
WriteThread(crashinfo.threads[i], 0);
|
||||
WriteThread(options, crashinfo.threads[i], 0);
|
||||
}
|
||||
|
||||
if (note_align) {
|
||||
google_breakpad::scoped_array<char> scratch(new char[note_align]);
|
||||
memset(scratch.get(), 0, note_align);
|
||||
if (!writea(1, scratch.get(), note_align))
|
||||
if (!writea(options.out_fd, scratch.get(), note_align))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1316,10 +1334,14 @@ main(int argc, const char* argv[]) {
|
|||
iter != crashinfo.mappings.end(); ++iter) {
|
||||
const CrashedProcess::Mapping& mapping = iter->second;
|
||||
if (mapping.data.size()) {
|
||||
if (!writea(1, mapping.data.c_str(), mapping.data.size()))
|
||||
if (!writea(options.out_fd, mapping.data.c_str(), mapping.data.size()))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.out_fd != STDOUT_FILENO) {
|
||||
close(options.out_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue