summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp')
-rw-r--r--toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp437
1 files changed, 0 insertions, 437 deletions
diff --git a/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp b/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp
deleted file mode 100644
index b523826c9..000000000
--- a/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp
+++ /dev/null
@@ -1,437 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <cstdio>
-#include <fstream>
-#include <string>
-#include <sstream>
-
-#include "json/json.h"
-#include "google_breakpad/processor/basic_source_line_resolver.h"
-#include "google_breakpad/processor/call_stack.h"
-#include "google_breakpad/processor/code_module.h"
-#include "google_breakpad/processor/code_modules.h"
-#include "google_breakpad/processor/minidump.h"
-#include "google_breakpad/processor/minidump_processor.h"
-#include "google_breakpad/processor/process_state.h"
-#include "google_breakpad/processor/stack_frame.h"
-#include "processor/pathname_stripper.h"
-
-#if defined(XP_WIN32)
-
-#include <windows.h>
-
-#elif defined(XP_UNIX) || defined(XP_MACOSX)
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#endif
-
-namespace CrashReporter {
-
-using std::ios;
-using std::ios_base;
-using std::hex;
-using std::ofstream;
-using std::map;
-using std::showbase;
-using std::string;
-using std::stringstream;
-using std::wstring;
-
-using google_breakpad::BasicSourceLineResolver;
-using google_breakpad::CallStack;
-using google_breakpad::CodeModule;
-using google_breakpad::CodeModules;
-using google_breakpad::Minidump;
-using google_breakpad::MinidumpProcessor;
-using google_breakpad::PathnameStripper;
-using google_breakpad::ProcessResult;
-using google_breakpad::ProcessState;
-using google_breakpad::StackFrame;
-
-#ifdef XP_WIN
-
-static wstring UTF8ToWide(const string& aUtf8Str, bool *aSuccess = nullptr)
-{
- wchar_t* buffer = nullptr;
- int buffer_size = MultiByteToWideChar(CP_UTF8, 0, aUtf8Str.c_str(),
- -1, nullptr, 0);
- if (buffer_size == 0) {
- if (aSuccess) {
- *aSuccess = false;
- }
-
- return L"";
- }
-
- buffer = new wchar_t[buffer_size];
-
- if (buffer == nullptr) {
- if (aSuccess) {
- *aSuccess = false;
- }
-
- return L"";
- }
-
- MultiByteToWideChar(CP_UTF8, 0, aUtf8Str.c_str(),
- -1, buffer, buffer_size);
- wstring str = buffer;
- delete [] buffer;
-
- if (aSuccess) {
- *aSuccess = true;
- }
-
- return str;
-}
-
-#endif
-
-struct ModuleCompare {
- bool operator() (const CodeModule* aLhs, const CodeModule* aRhs) const {
- return aLhs->base_address() < aRhs->base_address();
- }
-};
-
-typedef map<const CodeModule*, unsigned int, ModuleCompare> OrderedModulesMap;
-
-static const char kExtraDataExtension[] = ".extra";
-
-static string
-ToHex(uint64_t aValue) {
- stringstream output;
-
- output << hex << showbase << aValue;
-
- return output.str();
-}
-
-// Convert the stack frame trust value into a readable string.
-
-static string
-FrameTrust(const StackFrame::FrameTrust aTrust) {
- switch (aTrust) {
- case StackFrame::FRAME_TRUST_NONE:
- return "none";
- case StackFrame::FRAME_TRUST_SCAN:
- return "scan";
- case StackFrame::FRAME_TRUST_CFI_SCAN:
- return "cfi_scan";
- case StackFrame::FRAME_TRUST_FP:
- return "frame_pointer";
- case StackFrame::FRAME_TRUST_CFI:
- return "cfi";
- case StackFrame::FRAME_TRUST_PREWALKED:
- return "prewalked";
- case StackFrame::FRAME_TRUST_CONTEXT:
- return "context";
- }
-
- return "none";
-}
-
-// Convert the result value of the minidump processing step into a readable
-// string.
-
-static string
-ResultString(ProcessResult aResult) {
- switch (aResult) {
- case google_breakpad::PROCESS_OK:
- return "OK";
- case google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND:
- return "ERROR_MINIDUMP_NOT_FOUND";
- case google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER:
- return "ERROR_NO_MINIDUMP_HEADER";
- case google_breakpad::PROCESS_ERROR_NO_THREAD_LIST:
- return "ERROR_NO_THREAD_LIST";
- case google_breakpad::PROCESS_ERROR_GETTING_THREAD:
- return "ERROR_GETTING_THREAD";
- case google_breakpad::PROCESS_ERROR_GETTING_THREAD_ID:
- return "ERROR_GETTING_THREAD_ID";
- case google_breakpad::PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS:
- return "ERROR_DUPLICATE_REQUESTING_THREADS";
- case google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED:
- return "SYMBOL_SUPPLIER_INTERRUPTED";
- default:
- return "";
- }
-}
-
-// Convert the list of stack frames to JSON and append them to the array
-// specified in the |aNode| parameter.
-
-static void
-ConvertStackToJSON(const ProcessState& aProcessState,
- const OrderedModulesMap& aOrderedModules,
- const CallStack *aStack,
- Json::Value& aNode)
-{
- int frameCount = aStack->frames()->size();
- unsigned int moduleIndex = 0;
-
- for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
- const StackFrame *frame = aStack->frames()->at(frameIndex);
- Json::Value frameNode;
-
- if (frame->module) {
- auto itr = aOrderedModules.find(frame->module);
-
- if (itr != aOrderedModules.end()) {
- moduleIndex = (*itr).second;
- frameNode["module_index"] = moduleIndex;
- }
- }
-
- frameNode["trust"] = FrameTrust(frame->trust);
- // The 'ip' field is equivalent to socorro's 'offset' field
- frameNode["ip"] = ToHex(frame->instruction);
-
- aNode.append(frameNode);
- }
-}
-
-// Convert the list of modules to JSON and append them to the array specified
-// in the |aNode| parameter.
-
-static int
-ConvertModulesToJSON(const ProcessState& aProcessState,
- OrderedModulesMap& aOrderedModules,
- Json::Value& aNode)
-{
- const CodeModules* modules = aProcessState.modules();
-
- if (!modules) {
- return -1;
- }
-
- // Create a sorted set of modules so that we'll be able to lookup the index
- // of a particular module.
- for (unsigned int i = 0; i < modules->module_count(); ++i) {
- aOrderedModules.insert(
- std::pair<const CodeModule*, unsigned int>(
- modules->GetModuleAtSequence(i), i
- )
- );
- }
-
- uint64_t mainAddress = 0;
- const CodeModule *mainModule = modules->GetMainModule();
-
- if (mainModule) {
- mainAddress = mainModule->base_address();
- }
-
- unsigned int moduleCount = modules->module_count();
- int mainModuleIndex = -1;
-
- for (unsigned int moduleSequence = 0;
- moduleSequence < moduleCount;
- ++moduleSequence)
- {
- const CodeModule *module = modules->GetModuleAtSequence(moduleSequence);
-
- if (module->base_address() == mainAddress) {
- mainModuleIndex = moduleSequence;
- }
-
- Json::Value moduleNode;
- moduleNode["filename"] = PathnameStripper::File(module->code_file());
- moduleNode["code_id"] = PathnameStripper::File(module->code_identifier());
- moduleNode["version"] = module->version();
- moduleNode["debug_file"] = PathnameStripper::File(module->debug_file());
- moduleNode["debug_id"] = module->debug_identifier();
- moduleNode["base_addr"] = ToHex(module->base_address());
- moduleNode["end_addr"] = ToHex(module->base_address() + module->size());
-
- aNode.append(moduleNode);
- }
-
- return mainModuleIndex;
-}
-
-// Convert the process state to JSON, this includes information about the
-// crash, the module list and stack traces for every thread
-
-static void
-ConvertProcessStateToJSON(const ProcessState& aProcessState, Json::Value& aRoot)
-{
- // We use this map to get the index of a module when listed by address
- OrderedModulesMap orderedModules;
-
- // Crash info
- Json::Value crashInfo;
- int requestingThread = aProcessState.requesting_thread();
-
- if (aProcessState.crashed()) {
- crashInfo["type"] = aProcessState.crash_reason();
- crashInfo["address"] = ToHex(aProcessState.crash_address());
-
- if (requestingThread != -1) {
- crashInfo["crashing_thread"] = requestingThread;
- }
- } else {
- crashInfo["type"] = Json::Value(Json::nullValue);
- // Add assertion info, if available
- string assertion = aProcessState.assertion();
-
- if (!assertion.empty()) {
- crashInfo["assertion"] = assertion;
- }
- }
-
- aRoot["crash_info"] = crashInfo;
-
- // Modules
- Json::Value modules(Json::arrayValue);
- int mainModule = ConvertModulesToJSON(aProcessState, orderedModules, modules);
-
- if (mainModule != -1) {
- aRoot["main_module"] = mainModule;
- }
-
- aRoot["modules"] = modules;
-
- // Threads
- Json::Value threads(Json::arrayValue);
- int threadCount = aProcessState.threads()->size();
-
- for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) {
- Json::Value thread;
- Json::Value stack(Json::arrayValue);
- const CallStack* rawStack = aProcessState.threads()->at(threadIndex);
-
- ConvertStackToJSON(aProcessState, orderedModules, rawStack, stack);
- thread["frames"] = stack;
- threads.append(thread);
- }
-
- aRoot["threads"] = threads;
-}
-
-// Process the minidump file and append the JSON-formatted stack traces to
-// the node specified in |aRoot|
-
-static bool
-ProcessMinidump(Json::Value& aRoot, const string& aDumpFile) {
- BasicSourceLineResolver resolver;
- // We don't have a valid symbol resolver so we pass nullptr instead.
- MinidumpProcessor minidumpProcessor(nullptr, &resolver);
-
- // Process the minidump.
- Minidump dump(aDumpFile);
- if (!dump.Read()) {
- return false;
- }
-
- ProcessResult rv;
- ProcessState processState;
- rv = minidumpProcessor.Process(&dump, &processState);
- aRoot["status"] = ResultString(rv);
-
- ConvertProcessStateToJSON(processState, aRoot);
-
- return true;
-}
-
-// Open the specified file in append mode
-
-static ofstream*
-OpenAppend(const string& aFilename)
-{
- ios_base::openmode mode = ios::out | ios::app;
-
-#if defined(XP_WIN)
-#if defined(_MSC_VER)
- ofstream* file = new ofstream();
- file->open(UTF8ToWide(aFilename).c_str(), mode);
-#else // GCC
- ofstream* file =
- new ofstream(WideToMBCP(UTF8ToWide(aFilename), CP_ACP).c_str(), mode);
-#endif // _MSC_VER
-#else // Non-Windows
- ofstream* file = new ofstream(aFilename.c_str(), mode);
-#endif // XP_WIN
- return file;
-}
-
-// Check if a file exists at the specified path
-
-static bool
-FileExists(const string& aPath)
-{
-#if defined(XP_WIN)
- DWORD attrs = GetFileAttributes(UTF8ToWide(aPath).c_str());
- return (attrs != INVALID_FILE_ATTRIBUTES);
-#else // Non-Windows
- struct stat sb;
- int ret = stat(aPath.c_str(), &sb);
- if (ret == -1 || !(sb.st_mode & S_IFREG)) {
- return false;
- }
-
- return true;
-#endif // XP_WIN
-}
-
-// Update the extra data file by adding the StackTraces field holding the
-// JSON output of this program.
-
-static void
-UpdateExtraDataFile(const string &aDumpPath, const Json::Value& aRoot)
-{
- string extraDataPath(aDumpPath);
- int dot = extraDataPath.rfind('.');
-
- if (dot < 0) {
- return; // Not a valid dump path
- }
-
- extraDataPath.replace(dot, extraDataPath.length() - dot, kExtraDataExtension);
- ofstream* f = OpenAppend(extraDataPath.c_str());
-
- if (f->is_open()) {
- Json::FastWriter writer;
-
- *f << "StackTraces=" << writer.write(aRoot);
-
- f->close();
- }
-
- delete f;
-}
-
-} // namespace CrashReporter
-
-using namespace CrashReporter;
-
-int main(int argc, char** argv)
-{
- string dumpPath;
-
- if (argc > 1) {
- dumpPath = argv[1];
- }
-
- if (dumpPath.empty()) {
- exit(EXIT_FAILURE);
- }
-
- if (!FileExists(dumpPath)) {
- // The dump file does not exist
- return 1;
- }
-
- // Try processing the minidump
- Json::Value root;
- if (ProcessMinidump(root, dumpPath)) {
- UpdateExtraDataFile(dumpPath, root);
- }
-
- exit(EXIT_SUCCESS);
-}