minidump-2-core: rewrite argument processing

This uses the same general framework as other minidump tools by using
getopt to parse command line options, and then passing the parsed state
around as a struct rather than via globals.

This does change the --sobasedir flag to -S because we don't support
getopt_long anywhere in the tree.  Unfortunate, but better to match
all the other breakpad tools which only accept short options.

BUG=chromium:598947

Change-Id: I473081a29a8e3ef07a370848343f1a9e6681fd4e
Reviewed-on: https://chromium-review.googlesource.com/402908
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Mike Frysinger 2016-10-25 02:36:38 -04:00
parent 2ecb2baba8
commit ed7dcced19

View file

@ -30,8 +30,6 @@
// Converts a minidump file to a core file which gdb can read. // Converts a minidump file to a core file which gdb can read.
// Large parts lifted from the userspace core dumper: // Large parts lifted from the userspace core dumper:
// http://code.google.com/p/google-coredumper/ // http://code.google.com/p/google-coredumper/
//
// Usage: minidump-2-core [-v] 1234.dmp > core
#include <elf.h> #include <elf.h>
#include <errno.h> #include <errno.h>
@ -97,12 +95,64 @@ typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawDebug MDRawDebug;
typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawLinkMap MDRawLinkMap; typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawLinkMap MDRawLinkMap;
static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1); static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1);
static bool verbose;
static string g_custom_so_basedir;
static int usage(const char* argv0) { struct Options {
fprintf(stderr, "Usage: %s [-v] <minidump file>\n", argv0); string minidump_path;
return 1; bool verbose;
string so_basedir;
};
static void
Usage(int argc, const char* argv[]) {
fprintf(stderr,
"Usage: %s [options] <minidump file>\n"
"\n"
"Convert a minidump file into a core file (often for use by gdb).\n"
"\n"
"Options:\n"
" -v Enable verbose output\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"
" with a slash if it's a directory.\n"
"", basename(argv[0]));
}
static void
SetupOptions(int argc, const char* argv[], Options* options) {
extern int optind;
int ch;
// Initialize the options struct as needed.
options->verbose = false;
while ((ch = getopt(argc, (char * const *)argv, "hS:v")) != -1) {
switch (ch) {
case 'h':
Usage(argc, argv);
exit(0);
break;
case '?':
Usage(argc, argv);
exit(1);
break;
case 'S':
options->so_basedir = optarg;
break;
case 'v':
options->verbose = true;
break;
}
}
if ((argc - optind) != 1) {
fprintf(stderr, "%s: Missing minidump file\n", argv[0]);
Usage(argc, argv);
exit(1);
}
options->minidump_path = argv[optind];
} }
// Write all of the given buffer, handling short writes and EINTR. Return true // Write all of the given buffer, handling short writes and EINTR. Return true
@ -429,10 +479,11 @@ ParseThreadRegisters(CrashedProcess::Thread* thread,
#endif #endif
static void static void
ParseThreadList(CrashedProcess* crashinfo, const MinidumpMemoryRange& range, ParseThreadList(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range,
const MinidumpMemoryRange& full_file) { const MinidumpMemoryRange& full_file) {
const uint32_t num_threads = *range.GetData<uint32_t>(0); const uint32_t num_threads = *range.GetData<uint32_t>(0);
if (verbose) { if (options.verbose) {
fprintf(stderr, fprintf(stderr,
"MD_THREAD_LIST_STREAM:\n" "MD_THREAD_LIST_STREAM:\n"
"Found %d threads\n" "Found %d threads\n"
@ -459,12 +510,13 @@ ParseThreadList(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
} }
static void static void
ParseSystemInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range, ParseSystemInfo(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range,
const MinidumpMemoryRange& full_file) { const MinidumpMemoryRange& full_file) {
const MDRawSystemInfo* sysinfo = range.GetData<MDRawSystemInfo>(0); const MDRawSystemInfo* sysinfo = range.GetData<MDRawSystemInfo>(0);
if (!sysinfo) { if (!sysinfo) {
fprintf(stderr, "Failed to access MD_SYSTEM_INFO_STREAM\n"); fprintf(stderr, "Failed to access MD_SYSTEM_INFO_STREAM\n");
_exit(1); exit(1);
} }
#if defined(__i386__) #if defined(__i386__)
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_X86) { if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_X86) {
@ -472,7 +524,7 @@ ParseSystemInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
"This version of minidump-2-core only supports x86 (32bit)%s.\n", "This version of minidump-2-core only supports x86 (32bit)%s.\n",
sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 ? sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 ?
",\nbut the minidump file is from a 64bit machine" : ""); ",\nbut the minidump file is from a 64bit machine" : "");
_exit(1); exit(1);
} }
#elif defined(__x86_64__) #elif defined(__x86_64__)
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_AMD64) { if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_AMD64) {
@ -480,32 +532,32 @@ ParseSystemInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
"This version of minidump-2-core only supports x86 (64bit)%s.\n", "This version of minidump-2-core only supports x86 (64bit)%s.\n",
sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ? sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ?
",\nbut the minidump file is from a 32bit machine" : ""); ",\nbut the minidump file is from a 32bit machine" : "");
_exit(1); exit(1);
} }
#elif defined(__arm__) #elif defined(__arm__)
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM) { if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM) {
fprintf(stderr, fprintf(stderr,
"This version of minidump-2-core only supports ARM (32bit).\n"); "This version of minidump-2-core only supports ARM (32bit).\n");
_exit(1); exit(1);
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64) { if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64) {
fprintf(stderr, fprintf(stderr,
"This version of minidump-2-core only supports ARM (64bit).\n"); "This version of minidump-2-core only supports ARM (64bit).\n");
_exit(1); exit(1);
} }
#elif defined(__mips__) #elif defined(__mips__)
# if _MIPS_SIM == _ABIO32 # if _MIPS_SIM == _ABIO32
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS) { if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS) {
fprintf(stderr, fprintf(stderr,
"This version of minidump-2-core only supports mips o32 (32bit).\n"); "This version of minidump-2-core only supports mips o32 (32bit).\n");
_exit(1); exit(1);
} }
# elif _MIPS_SIM == _ABI64 # elif _MIPS_SIM == _ABI64
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS64) { if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS64) {
fprintf(stderr, fprintf(stderr,
"This version of minidump-2-core only supports mips n64 (64bit).\n"); "This version of minidump-2-core only supports mips n64 (64bit).\n");
_exit(1); exit(1);
} }
# else # else
# error "This mips ABI is currently not supported (n32)" # error "This mips ABI is currently not supported (n32)"
@ -517,10 +569,10 @@ ParseSystemInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
"Linux") && "Linux") &&
sysinfo->platform_id != MD_OS_NACL) { sysinfo->platform_id != MD_OS_NACL) {
fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n"); fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n");
_exit(1); exit(1);
} }
if (verbose) { if (options.verbose) {
fprintf(stderr, fprintf(stderr,
"MD_SYSTEM_INFO_STREAM:\n" "MD_SYSTEM_INFO_STREAM:\n"
"Architecture: %s\n" "Architecture: %s\n"
@ -561,8 +613,9 @@ ParseSystemInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
} }
static void static void
ParseCPUInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { ParseCPUInfo(const Options& options, CrashedProcess* crashinfo,
if (verbose) { const MinidumpMemoryRange& range) {
if (options.verbose) {
fputs("MD_LINUX_CPU_INFO:\n", stderr); fputs("MD_LINUX_CPU_INFO:\n", stderr);
fwrite(range.data(), range.length(), 1, stderr); fwrite(range.data(), range.length(), 1, stderr);
fputs("\n\n\n", stderr); fputs("\n\n\n", stderr);
@ -570,9 +623,9 @@ ParseCPUInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
} }
static void static void
ParseProcessStatus(CrashedProcess* crashinfo, ParseProcessStatus(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range) { const MinidumpMemoryRange& range) {
if (verbose) { if (options.verbose) {
fputs("MD_LINUX_PROC_STATUS:\n", stderr); fputs("MD_LINUX_PROC_STATUS:\n", stderr);
fwrite(range.data(), range.length(), 1, stderr); fwrite(range.data(), range.length(), 1, stderr);
fputs("\n\n", stderr); fputs("\n\n", stderr);
@ -580,8 +633,9 @@ ParseProcessStatus(CrashedProcess* crashinfo,
} }
static void static void
ParseLSBRelease(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { ParseLSBRelease(const Options& options, CrashedProcess* crashinfo,
if (verbose) { const MinidumpMemoryRange& range) {
if (options.verbose) {
fputs("MD_LINUX_LSB_RELEASE:\n", stderr); fputs("MD_LINUX_LSB_RELEASE:\n", stderr);
fwrite(range.data(), range.length(), 1, stderr); fwrite(range.data(), range.length(), 1, stderr);
fputs("\n\n", stderr); fputs("\n\n", stderr);
@ -589,8 +643,9 @@ ParseLSBRelease(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
} }
static void static void
ParseMaps(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { ParseMaps(const Options& options, CrashedProcess* crashinfo,
if (verbose) { const MinidumpMemoryRange& range) {
if (options.verbose) {
fputs("MD_LINUX_MAPS:\n", stderr); fputs("MD_LINUX_MAPS:\n", stderr);
fwrite(range.data(), range.length(), 1, stderr); fwrite(range.data(), range.length(), 1, stderr);
} }
@ -629,14 +684,15 @@ ParseMaps(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
free(permissions); free(permissions);
free(filename); free(filename);
} }
if (verbose) { if (options.verbose) {
fputs("\n\n\n", stderr); fputs("\n\n\n", stderr);
} }
} }
static void static void
ParseEnvironment(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { ParseEnvironment(const Options& options, CrashedProcess* crashinfo,
if (verbose) { const MinidumpMemoryRange& range) {
if (options.verbose) {
fputs("MD_LINUX_ENVIRON:\n", stderr); fputs("MD_LINUX_ENVIRON:\n", stderr);
char* env = new char[range.length()]; char* env = new char[range.length()];
memcpy(env, range.data(), range.length()); memcpy(env, range.data(), range.length());
@ -673,7 +729,8 @@ ParseEnvironment(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
} }
static void static void
ParseAuxVector(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { ParseAuxVector(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range) {
// Some versions of Chrome erroneously used the MD_LINUX_AUXV stream value // Some versions of Chrome erroneously used the MD_LINUX_AUXV stream value
// when dumping /proc/$x/maps // when dumping /proc/$x/maps
if (range.length() > 17) { if (range.length() > 17) {
@ -684,7 +741,7 @@ ParseAuxVector(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
memcpy(addresses, range.data(), 17); memcpy(addresses, range.data(), 17);
addresses[17] = '\000'; addresses[17] = '\000';
if (strspn(addresses, "0123456789abcdef-") == 17) { if (strspn(addresses, "0123456789abcdef-") == 17) {
ParseMaps(crashinfo, range); ParseMaps(options, crashinfo, range);
return; return;
} }
} }
@ -694,12 +751,13 @@ ParseAuxVector(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
} }
static void static void
ParseCmdLine(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { ParseCmdLine(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range) {
// The command line is supposed to use NUL bytes to separate arguments. // The command line is supposed to use NUL bytes to separate arguments.
// As Chrome rewrites its own command line and (incorrectly) substitutes // As Chrome rewrites its own command line and (incorrectly) substitutes
// spaces, this is often not the case in our minidump files. // spaces, this is often not the case in our minidump files.
const char* cmdline = (const char*) range.data(); const char* cmdline = (const char*) range.data();
if (verbose) { if (options.verbose) {
fputs("MD_LINUX_CMD_LINE:\n", stderr); fputs("MD_LINUX_CMD_LINE:\n", stderr);
unsigned i = 0; unsigned i = 0;
for (; i < range.length() && cmdline[i] && cmdline[i] != ' '; ++i) { } for (; i < range.length() && cmdline[i] && cmdline[i] != ' '; ++i) { }
@ -742,13 +800,14 @@ ParseCmdLine(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
} }
static void static void
ParseDSODebugInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range, ParseDSODebugInfo(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range,
const MinidumpMemoryRange& full_file) { const MinidumpMemoryRange& full_file) {
const MDRawDebug* debug = range.GetData<MDRawDebug>(0); const MDRawDebug* debug = range.GetData<MDRawDebug>(0);
if (!debug) { if (!debug) {
return; return;
} }
if (verbose) { if (options.verbose) {
fprintf(stderr, fprintf(stderr,
"MD_LINUX_DSO_DEBUG:\n" "MD_LINUX_DSO_DEBUG:\n"
"Version: %d\n" "Version: %d\n"
@ -773,7 +832,7 @@ ParseDSODebugInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
const MDRawLinkMap* link_map = const MDRawLinkMap* link_map =
full_file.GetArrayElement<MDRawLinkMap>(debug->map, i); full_file.GetArrayElement<MDRawLinkMap>(debug->map, i);
if (link_map) { if (link_map) {
if (verbose) { if (options.verbose) {
fprintf(stderr, fprintf(stderr,
"#%03d: %" PRIx64 ", %" PRIx64 ", \"%s\"\n", "#%03d: %" PRIx64 ", %" PRIx64 ", \"%s\"\n",
i, static_cast<uint64_t>(link_map->addr), i, static_cast<uint64_t>(link_map->addr),
@ -784,13 +843,13 @@ ParseDSODebugInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
} }
} }
} }
if (verbose) { if (options.verbose) {
fputs("\n\n", stderr); fputs("\n\n", stderr);
} }
} }
static void static void
ParseExceptionStream(CrashedProcess* crashinfo, ParseExceptionStream(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range) { const MinidumpMemoryRange& range) {
const MDRawExceptionStream* exp = range.GetData<MDRawExceptionStream>(0); const MDRawExceptionStream* exp = range.GetData<MDRawExceptionStream>(0);
crashinfo->crashing_tid = exp->thread_id; crashinfo->crashing_tid = exp->thread_id;
@ -846,9 +905,10 @@ WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
} }
static void static void
ParseModuleStream(CrashedProcess* crashinfo, const MinidumpMemoryRange& range, ParseModuleStream(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range,
const MinidumpMemoryRange& full_file) { const MinidumpMemoryRange& full_file) {
if (verbose) { if (options.verbose) {
fputs("MD_MODULE_LIST_STREAM:\n", stderr); fputs("MD_MODULE_LIST_STREAM:\n", stderr);
} }
const uint32_t num_mappings = *range.GetData<uint32_t>(0); const uint32_t num_mappings = *range.GetData<uint32_t>(0);
@ -883,15 +943,15 @@ ParseModuleStream(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
filename : filename.substr(slash + 1); filename : filename.substr(slash + 1);
if (strcmp(guid, "00000000-0000-0000-0000-000000000000")) { if (strcmp(guid, "00000000-0000-0000-0000-000000000000")) {
string prefix; string prefix;
if (!g_custom_so_basedir.empty()) if (!options.so_basedir.empty())
prefix = g_custom_so_basedir; prefix = options.so_basedir;
else else
prefix = string("/var/lib/breakpad/") + guid + "-" + basename; prefix = string("/var/lib/breakpad/") + guid + "-" + basename;
crashinfo->signatures[rawmodule->base_of_image] = prefix + basename; crashinfo->signatures[rawmodule->base_of_image] = prefix + basename;
} }
if (verbose) { if (options.verbose) {
fprintf(stderr, "0x%08llX-0x%08llX, ChkSum: 0x%08X, GUID: %s, \"%s\"\n", fprintf(stderr, "0x%08llX-0x%08llX, ChkSum: 0x%08X, GUID: %s, \"%s\"\n",
(unsigned long long)rawmodule->base_of_image, (unsigned long long)rawmodule->base_of_image,
(unsigned long long)rawmodule->base_of_image + (unsigned long long)rawmodule->base_of_image +
@ -899,7 +959,7 @@ ParseModuleStream(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
rawmodule->checksum, guid, filename.c_str()); rawmodule->checksum, guid, filename.c_str());
} }
} }
if (verbose) { if (options.verbose) {
fputs("\n\n", stderr); fputs("\n\n", stderr);
} }
} }
@ -954,7 +1014,7 @@ AddDataToMapping(CrashedProcess* crashinfo, const string& data,
} }
static void static void
AugmentMappings(CrashedProcess* crashinfo, AugmentMappings(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& full_file) { const MinidumpMemoryRange& full_file) {
// For each thread, find the memory mapping that matches the thread's stack. // For each thread, find the memory mapping that matches the thread's stack.
// Then adjust the mapping to include the stack dump. // Then adjust the mapping to include the stack dump.
@ -1019,7 +1079,7 @@ AugmentMappings(CrashedProcess* crashinfo,
ElfW(Dyn) dyn; ElfW(Dyn) dyn;
if ((i+1)*sizeof(dyn) > crashinfo->dynamic_data.length()) { if ((i+1)*sizeof(dyn) > crashinfo->dynamic_data.length()) {
no_dt_debug: no_dt_debug:
if (verbose) { if (options.verbose) {
fprintf(stderr, "No DT_DEBUG entry found\n"); fprintf(stderr, "No DT_DEBUG entry found\n");
} }
return; return;
@ -1042,31 +1102,14 @@ AugmentMappings(CrashedProcess* crashinfo,
} }
int int
main(int argc, char** argv) { main(int argc, const char* argv[]) {
int argi = 1; Options options;
while (argi < argc && argv[argi][0] == '-') { SetupOptions(argc, argv, &options);
if (!strcmp(argv[argi], "-v")) {
verbose = true;
} else if (!strcmp(argv[argi], "--sobasedir")) {
argi++;
if (argi >= argc) {
fprintf(stderr, "--sobasedir expects an argument.");
return usage(argv[0]);
}
g_custom_so_basedir = argv[argi]; MemoryMappedFile mapped_file(options.minidump_path.c_str(), 0);
} else {
return usage(argv[0]);
}
argi++;
}
if (argc != argi + 1)
return usage(argv[0]);
MemoryMappedFile mapped_file(argv[argi], 0);
if (!mapped_file.data()) { if (!mapped_file.data()) {
fprintf(stderr, "Failed to mmap dump file\n"); fprintf(stderr, "Failed to mmap dump file: %s: %s\n",
options.minidump_path.c_str(), strerror(errno));
return 1; return 1;
} }
@ -1084,7 +1127,8 @@ main(int argc, char** argv) {
dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i); dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i);
switch (dirent->stream_type) { switch (dirent->stream_type) {
case MD_SYSTEM_INFO_STREAM: case MD_SYSTEM_INFO_STREAM:
ParseSystemInfo(&crashinfo, dump.Subrange(dirent->location), dump); ParseSystemInfo(options, &crashinfo, dump.Subrange(dirent->location),
dump);
ok = true; ok = true;
break; break;
default: default:
@ -1093,7 +1137,7 @@ main(int argc, char** argv) {
} }
if (!ok) { if (!ok) {
fprintf(stderr, "Cannot determine input file format.\n"); fprintf(stderr, "Cannot determine input file format.\n");
_exit(1); exit(1);
} }
for (unsigned i = 0; i < header->stream_count; ++i) { for (unsigned i = 0; i < header->stream_count; ++i) {
@ -1101,45 +1145,50 @@ main(int argc, char** argv) {
dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i); dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i);
switch (dirent->stream_type) { switch (dirent->stream_type) {
case MD_THREAD_LIST_STREAM: case MD_THREAD_LIST_STREAM:
ParseThreadList(&crashinfo, dump.Subrange(dirent->location), dump); ParseThreadList(options, &crashinfo, dump.Subrange(dirent->location),
dump);
break; break;
case MD_LINUX_CPU_INFO: case MD_LINUX_CPU_INFO:
ParseCPUInfo(&crashinfo, dump.Subrange(dirent->location)); ParseCPUInfo(options, &crashinfo, dump.Subrange(dirent->location));
break; break;
case MD_LINUX_PROC_STATUS: case MD_LINUX_PROC_STATUS:
ParseProcessStatus(&crashinfo, dump.Subrange(dirent->location)); ParseProcessStatus(options, &crashinfo,
dump.Subrange(dirent->location));
break; break;
case MD_LINUX_LSB_RELEASE: case MD_LINUX_LSB_RELEASE:
ParseLSBRelease(&crashinfo, dump.Subrange(dirent->location)); ParseLSBRelease(options, &crashinfo, dump.Subrange(dirent->location));
break; break;
case MD_LINUX_ENVIRON: case MD_LINUX_ENVIRON:
ParseEnvironment(&crashinfo, dump.Subrange(dirent->location)); ParseEnvironment(options, &crashinfo, dump.Subrange(dirent->location));
break; break;
case MD_LINUX_MAPS: case MD_LINUX_MAPS:
ParseMaps(&crashinfo, dump.Subrange(dirent->location)); ParseMaps(options, &crashinfo, dump.Subrange(dirent->location));
break; break;
case MD_LINUX_AUXV: case MD_LINUX_AUXV:
ParseAuxVector(&crashinfo, dump.Subrange(dirent->location)); ParseAuxVector(options, &crashinfo, dump.Subrange(dirent->location));
break; break;
case MD_LINUX_CMD_LINE: case MD_LINUX_CMD_LINE:
ParseCmdLine(&crashinfo, dump.Subrange(dirent->location)); ParseCmdLine(options, &crashinfo, dump.Subrange(dirent->location));
break; break;
case MD_LINUX_DSO_DEBUG: case MD_LINUX_DSO_DEBUG:
ParseDSODebugInfo(&crashinfo, dump.Subrange(dirent->location), dump); ParseDSODebugInfo(options, &crashinfo, dump.Subrange(dirent->location),
dump);
break; break;
case MD_EXCEPTION_STREAM: case MD_EXCEPTION_STREAM:
ParseExceptionStream(&crashinfo, dump.Subrange(dirent->location)); ParseExceptionStream(options, &crashinfo,
dump.Subrange(dirent->location));
break; break;
case MD_MODULE_LIST_STREAM: case MD_MODULE_LIST_STREAM:
ParseModuleStream(&crashinfo, dump.Subrange(dirent->location), dump); ParseModuleStream(options, &crashinfo, dump.Subrange(dirent->location),
dump);
break; break;
default: default:
if (verbose) if (options.verbose)
fprintf(stderr, "Skipping %x\n", dirent->stream_type); fprintf(stderr, "Skipping %x\n", dirent->stream_type);
} }
} }
AugmentMappings(&crashinfo, dump); AugmentMappings(options, &crashinfo, dump);
// Write the ELF header. The file will look like: // Write the ELF header. The file will look like:
// ELF header // ELF header