tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CrashReporterHost.cpp (7319B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "CrashReporterHost.h"
      8 #include "CrashReporter/CrashReporterInitArgs.h"
      9 #include "mozilla/dom/Promise.h"
     10 #include "mozilla/Sprintf.h"
     11 #include "mozilla/SyncRunnable.h"
     12 #include "mozilla/glean/IpcMetrics.h"
     13 #include "nsServiceManagerUtils.h"
     14 #include "nsICrashService.h"
     15 #include "nsXULAppAPI.h"
     16 #include "nsIFile.h"
     17 
     18 #if defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && \
     19    defined(MOZ_OXIDIZED_BREAKPAD)
     20 #  include "mozilla/toolkit/crashreporter/rust_minidump_writer_linux_ffi_generated.h"
     21 #endif  // defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) &&
     22        // defined(MOZ_OXIDIZED_BREAKPAD)
     23 
     24 namespace mozilla::ipc {
     25 
     26 CrashReporterHost::CrashReporterHost(
     27    GeckoProcessType aProcessType, base::ProcessId aPid,
     28    const CrashReporter::CrashReporterInitArgs& aInitArgs)
     29    : mProcessType(aProcessType),
     30      mPid(aPid),
     31      mThreadId(aInitArgs.threadId()),
     32      mStartTime(::time(nullptr)),
     33      mFinalized(false) {
     34 #if defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && \
     35    defined(MOZ_OXIDIZED_BREAKPAD)
     36  const CrashReporter::AuxvInfo& ipdlAuxvInfo = aInitArgs.auxvInfo();
     37  DirectAuxvDumpInfo auxvInfo = {};
     38  auxvInfo.program_header_count = ipdlAuxvInfo.programHeaderCount();
     39  auxvInfo.program_header_address = ipdlAuxvInfo.programHeaderAddress();
     40  auxvInfo.linux_gate_address = ipdlAuxvInfo.linuxGateAddress();
     41  auxvInfo.entry_address = ipdlAuxvInfo.entryAddress();
     42  CrashReporter::RegisterChildAuxvInfo(mPid, auxvInfo);
     43 #endif  // defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) &&
     44        // defined(MOZ_OXIDIZED_BREAKPAD)
     45 }
     46 
     47 CrashReporterHost::~CrashReporterHost() {
     48 #if defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && \
     49    defined(MOZ_OXIDIZED_BREAKPAD)
     50  CrashReporter::UnregisterChildAuxvInfo(mPid);
     51 #endif  // defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) &&
     52        // defined(MOZ_OXIDIZED_BREAKPAD)
     53 }
     54 
     55 bool CrashReporterHost::GenerateCrashReport() {
     56  if (!TakeCrashedChildMinidump()) {
     57    return false;
     58  }
     59 
     60  FinalizeCrashReport();
     61  RecordCrash(mProcessType, nsICrashService::CRASH_TYPE_CRASH, mDumpID);
     62  return true;
     63 }
     64 
     65 RefPtr<nsIFile> CrashReporterHost::TakeCrashedChildMinidump() {
     66  CrashReporter::AnnotationTable annotations;
     67  MOZ_ASSERT(!HasMinidump());
     68 
     69  RefPtr<nsIFile> crashDump;
     70  if (!CrashReporter::TakeMinidumpForChild(mPid, getter_AddRefs(crashDump),
     71                                           annotations)) {
     72    return nullptr;
     73  }
     74  if (!AdoptMinidump(crashDump, annotations)) {
     75    return nullptr;
     76  }
     77  return crashDump;
     78 }
     79 
     80 bool CrashReporterHost::AdoptMinidump(nsIFile* aFile,
     81                                      const AnnotationTable& aAnnotations) {
     82  if (!CrashReporter::GetIDFromMinidump(aFile, mDumpID)) {
     83    return false;
     84  }
     85 
     86  MergeCrashAnnotations(mExtraAnnotations, aAnnotations);
     87  return true;
     88 }
     89 
     90 void CrashReporterHost::FinalizeCrashReport() {
     91  MOZ_ASSERT(!mFinalized);
     92  MOZ_ASSERT(HasMinidump());
     93 
     94  mExtraAnnotations[CrashReporter::Annotation::ProcessType] = ProcessType();
     95 
     96  char startTime[32];
     97  SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
     98  mExtraAnnotations[CrashReporter::Annotation::StartupTime] =
     99      nsDependentCString(startTime);
    100 
    101  CrashReporter::WriteExtraFile(mDumpID, mExtraAnnotations);
    102  mFinalized = true;
    103 }
    104 
    105 void CrashReporterHost::DeleteCrashReport() {
    106  if (mFinalized && HasMinidump()) {
    107    CrashReporter::DeleteMinidumpFilesForID(mDumpID, Some(u"browser"_ns));
    108  }
    109 }
    110 
    111 const char* CrashReporterHost::ProcessType() const {
    112  return XRE_ChildProcessTypeToAnnotation(mProcessType);
    113 }
    114 
    115 /* static */
    116 void CrashReporterHost::RecordCrash(GeckoProcessType aProcessType,
    117                                    int32_t aCrashType,
    118                                    const nsString& aChildDumpID) {
    119  if (!NS_IsMainThread()) {
    120    RefPtr<Runnable> runnable = NS_NewRunnableFunction(
    121        "ipc::CrashReporterHost::RecordCrash", [&]() -> void {
    122          CrashReporterHost::RecordCrash(aProcessType, aCrashType,
    123                                         aChildDumpID);
    124        });
    125    RefPtr<nsIThread> mainThread = do_GetMainThread();
    126    SyncRunnable::DispatchToThread(mainThread, runnable);
    127    return;
    128  }
    129 
    130  RecordCrashWithTelemetry(aProcessType, aCrashType);
    131  NotifyCrashService(aProcessType, aCrashType, aChildDumpID);
    132 }
    133 
    134 /* static */
    135 void CrashReporterHost::RecordCrashWithTelemetry(GeckoProcessType aProcessType,
    136                                                 int32_t aCrashType) {
    137  nsCString key;
    138 
    139  switch (aProcessType) {
    140 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
    141                           process_bin_type, procinfo_typename,               \
    142                           webidl_typename, allcaps_name)                     \
    143  case GeckoProcessType_##enum_name:                                          \
    144    key.AssignLiteral(string_name);                                           \
    145    break;
    146 #include "mozilla/GeckoProcessTypes.h"
    147 #undef GECKO_PROCESS_TYPE
    148    // We can't really hit this, thanks to the above switch, but having it
    149    // here will placate the compiler.
    150    default:
    151      MOZ_ASSERT_UNREACHABLE("unknown process type");
    152  }
    153 
    154  glean::subprocess::crashes_with_dump.Get(key).Add(1);
    155 }
    156 
    157 /* static */
    158 void CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType,
    159                                           int32_t aCrashType,
    160                                           const nsString& aChildDumpID) {
    161  MOZ_ASSERT(!aChildDumpID.IsEmpty());
    162 
    163  nsCOMPtr<nsICrashService> crashService =
    164      do_GetService("@mozilla.org/crashservice;1");
    165  if (!crashService) {
    166    return;
    167  }
    168 
    169  int32_t processType;
    170 
    171  switch (aProcessType) {
    172    case GeckoProcessType_IPDLUnitTest:
    173    case GeckoProcessType_Default:
    174      NS_ERROR("unknown process type");
    175      return;
    176    default:
    177      processType = (int)aProcessType;
    178      break;
    179  }
    180 
    181  RefPtr<dom::Promise> promise;
    182  crashService->AddCrash(processType, aCrashType, aChildDumpID,
    183                         getter_AddRefs(promise));
    184 }
    185 
    186 void CrashReporterHost::AddAnnotationBool(CrashReporter::Annotation aKey,
    187                                          bool aValue) {
    188  MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::Boolean,
    189             "Wrong annotation type");
    190  mExtraAnnotations[aKey] = aValue ? "1"_ns : "0"_ns;
    191 }
    192 
    193 void CrashReporterHost::AddAnnotationU32(CrashReporter::Annotation aKey,
    194                                         uint32_t aValue) {
    195  MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::U32,
    196             "Wrong annotation type");
    197  nsAutoCString valueString;
    198  valueString.AppendInt(aValue);
    199  mExtraAnnotations[aKey] = valueString;
    200 }
    201 
    202 void CrashReporterHost::AddAnnotationNSCString(CrashReporter::Annotation aKey,
    203                                               const nsACString& aValue) {
    204  MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::String,
    205             "Wrong annotation type");
    206  mExtraAnnotations[aKey] = aValue;
    207 }
    208 
    209 }  // namespace mozilla::ipc