extended_crash_reporting.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/browser_watcher/extended_crash_reporting.h"
  5. #include <windows.h>
  6. #include <memory>
  7. #include "base/debug/activity_tracker.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/metrics/persistent_memory_allocator.h"
  10. #include "base/strings/string_piece.h"
  11. #include "base/time/time.h"
  12. #include "base/win/pe_image.h"
  13. #include "build/build_config.h"
  14. #include "components/browser_watcher/activity_data_names.h"
  15. #include "components/browser_watcher/activity_report.pb.h"
  16. #include "components/browser_watcher/activity_tracker_annotation.h"
  17. #include "components/browser_watcher/extended_crash_reporting.h"
  18. #include "components/browser_watcher/extended_crash_reporting_metrics.h"
  19. #include "components/browser_watcher/features.h"
  20. #if BUILDFLAG(IS_WIN)
  21. // https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483.
  22. extern "C" IMAGE_DOS_HEADER __ImageBase;
  23. #endif
  24. namespace browser_watcher {
  25. namespace {
  26. ExtendedCrashReporting* g_instance = nullptr;
  27. uintptr_t GetProgramCounter(const CONTEXT& context) {
  28. #if defined(ARCH_CPU_X86)
  29. return context.Eip;
  30. #elif defined(ARCH_CPU_X86_64)
  31. return context.Rip;
  32. #elif defined(ARCH_CPU_ARM64)
  33. return context.Pc;
  34. #endif
  35. }
  36. LONG CALLBACK VectoredExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
  37. base::debug::GlobalActivityTracker* tracker =
  38. base::debug::GlobalActivityTracker::Get();
  39. if (tracker) {
  40. EXCEPTION_RECORD* record = exception_pointers->ExceptionRecord;
  41. uintptr_t pc = GetProgramCounter(*exception_pointers->ContextRecord);
  42. tracker->RecordException(reinterpret_cast<void*>(pc),
  43. record->ExceptionAddress, record->ExceptionCode);
  44. }
  45. return EXCEPTION_CONTINUE_SEARCH; // Continue to the next handler.
  46. }
  47. // Record information about the chrome module.
  48. void RecordChromeModuleInfo(
  49. base::debug::GlobalActivityTracker* global_tracker) {
  50. DCHECK(global_tracker);
  51. base::debug::GlobalActivityTracker::ModuleInfo module;
  52. module.is_loaded = true;
  53. module.address = reinterpret_cast<uintptr_t>(&__ImageBase);
  54. base::win::PEImage pe(&__ImageBase);
  55. PIMAGE_NT_HEADERS headers = pe.GetNTHeaders();
  56. CHECK(headers);
  57. module.size = headers->OptionalHeader.SizeOfImage;
  58. module.timestamp = headers->FileHeader.TimeDateStamp;
  59. GUID guid;
  60. DWORD age;
  61. LPCSTR pdb_filename = nullptr;
  62. size_t pdb_filename_length = 0;
  63. if (pe.GetDebugId(&guid, &age, &pdb_filename, &pdb_filename_length)) {
  64. module.age = age;
  65. static_assert(sizeof(module.identifier) >= sizeof(guid),
  66. "Identifier field must be able to contain a GUID.");
  67. memcpy(module.identifier, &guid, sizeof(guid));
  68. } else {
  69. memset(module.identifier, 0, sizeof(module.identifier));
  70. }
  71. module.file = "chrome.dll";
  72. module.debug_file =
  73. std::string(base::StringPiece(pdb_filename, pdb_filename_length));
  74. global_tracker->RecordModuleInfo(module);
  75. }
  76. } // namespace
  77. ExtendedCrashReporting::ExtendedCrashReporting(
  78. base::debug::GlobalActivityTracker* tracker)
  79. : tracker_(tracker) {}
  80. ExtendedCrashReporting::~ExtendedCrashReporting() {
  81. if (veh_handle_)
  82. ::RemoveVectoredExceptionHandler(veh_handle_);
  83. }
  84. ExtendedCrashReporting* ExtendedCrashReporting::SetUpIfEnabled(
  85. ProcessType process_type) {
  86. DCHECK_EQ(nullptr, g_instance);
  87. if (!base::FeatureList::IsEnabled(kExtendedCrashReportingFeature)) {
  88. return nullptr;
  89. }
  90. return SetUpImpl(process_type);
  91. }
  92. ExtendedCrashReporting* ExtendedCrashReporting::GetInstance() {
  93. return g_instance;
  94. }
  95. void ExtendedCrashReporting::SetProductStrings(
  96. const std::u16string& product_name,
  97. const std::u16string& product_version,
  98. const std::u16string& channel_name,
  99. const std::u16string& special_build) {
  100. base::debug::ActivityUserData& proc_data = tracker_->process_data();
  101. proc_data.SetString(kActivityProduct, product_name);
  102. proc_data.SetString(kActivityVersion, product_version);
  103. proc_data.SetString(kActivityChannel, channel_name);
  104. proc_data.SetString(kActivitySpecialBuild, special_build);
  105. }
  106. void ExtendedCrashReporting::SetBool(base::StringPiece name, bool value) {
  107. tracker_->process_data().SetBool(name, value);
  108. }
  109. void ExtendedCrashReporting::SetInt(base::StringPiece name, int64_t value) {
  110. tracker_->process_data().SetInt(name, value);
  111. }
  112. void ExtendedCrashReporting::SetDataBool(base::StringPiece name, bool value) {
  113. if (g_instance)
  114. g_instance->SetBool(name, value);
  115. }
  116. void ExtendedCrashReporting::SetDataInt(base::StringPiece name, int64_t value) {
  117. if (g_instance)
  118. g_instance->SetInt(name, value);
  119. }
  120. void ExtendedCrashReporting::RegisterVEH() {
  121. #if defined(ADDRESS_SANITIZER)
  122. // ASAN on windows x64 is dynamically allocating the shadow memory on a
  123. // memory access violation by setting up an vector exception handler.
  124. // When instrumented with ASAN, this code may trigger an exception by
  125. // accessing unallocated shadow memory, which is causing an infinite
  126. // recursion (i.e. infinite memory access violation).
  127. (void)&VectoredExceptionHandler;
  128. #else
  129. DCHECK_EQ(nullptr, veh_handle_);
  130. // Register a vectored exception handler and request it be first. Note that
  131. // subsequent registrations may also request to be first, in which case this
  132. // one will be bumped.
  133. // TODO(manzagop): Depending on observations, it may be necessary to
  134. // consider refreshing the registration, either periodically or at opportune
  135. // (e.g. risky) times.
  136. veh_handle_ = ::AddVectoredExceptionHandler(1, &VectoredExceptionHandler);
  137. DCHECK(veh_handle_);
  138. #endif // ADDRESS_SANITIZER
  139. }
  140. void ExtendedCrashReporting::SetUpForTesting() {
  141. ExtendedCrashReporting::SetUpImpl(kBrowserProcess);
  142. }
  143. void ExtendedCrashReporting::TearDownForTesting() {
  144. if (g_instance) {
  145. ExtendedCrashReporting* instance_to_delete = g_instance;
  146. g_instance = nullptr;
  147. delete instance_to_delete;
  148. }
  149. // Clear the crash annotation.
  150. ActivityTrackerAnnotation::GetInstance()->Clear();
  151. }
  152. ExtendedCrashReporting* ExtendedCrashReporting::SetUpImpl(
  153. ProcessType process_type) {
  154. DCHECK_EQ(nullptr, g_instance);
  155. // TODO(https://crbug.com/1044707): Adjust these numbers once there is real
  156. // data to show just how much of an arena is necessary.
  157. const size_t kMemorySize = 1 << 20; // 1 MiB
  158. const int kStackDepth = 4;
  159. const uint64_t kAllocatorId = 0;
  160. base::debug::GlobalActivityTracker::CreateWithAllocator(
  161. std::make_unique<base::LocalPersistentMemoryAllocator>(
  162. kMemorySize, kAllocatorId, kExtendedCrashReportingFeature.name),
  163. kStackDepth, 0);
  164. // Track code activities (such as posting task, blocking on locks, and
  165. // joining threads) that can cause hanging threads and general instability
  166. base::debug::GlobalActivityTracker* global_tracker =
  167. base::debug::GlobalActivityTracker::Get();
  168. DCHECK(global_tracker);
  169. // Construct the instance with the new global tracker, this object is
  170. // intentionally leaked.
  171. std::unique_ptr<ExtendedCrashReporting> new_instance =
  172. base::WrapUnique(new ExtendedCrashReporting(global_tracker));
  173. new_instance->Initialize(process_type);
  174. g_instance = new_instance.release();
  175. return g_instance;
  176. }
  177. void ExtendedCrashReporting::Initialize(ProcessType process_type) {
  178. // Record the location and size of the tracker memory range in a Crashpad
  179. // annotation to allow the handler to retrieve it on crash.
  180. // Record the buffer size and location for the annotation beacon.
  181. auto* allocator = tracker_->allocator();
  182. ActivityTrackerAnnotation::GetInstance()->SetValue(allocator->data(),
  183. allocator->size());
  184. // Record the main DLL module info for easier symbolization.
  185. RecordChromeModuleInfo(tracker_);
  186. LogActivityRecordEvent(ActivityRecordEvent::kGotTracker);
  187. base::debug::ActivityUserData& proc_data = tracker_->process_data();
  188. #if defined(ARCH_CPU_X86)
  189. proc_data.SetString(kActivityPlatform, "Win32");
  190. #elif defined(ARCH_CPU_X86_64)
  191. proc_data.SetString(kActivityPlatform, "Win64");
  192. #endif
  193. proc_data.SetInt(
  194. kActivityStartTimestamp,
  195. base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
  196. if (process_type == kBrowserProcess)
  197. proc_data.SetInt(kActivityProcessType, ProcessState::BROWSER_PROCESS);
  198. RegisterVEH();
  199. }
  200. } // namespace browser_watcher