minidump_misc_info_writer.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // Copyright 2014 The Crashpad Authors. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "minidump/minidump_misc_info_writer.h"
  15. #include <iterator>
  16. #include <limits>
  17. #include "base/check_op.h"
  18. #include "base/logging.h"
  19. #include "base/numerics/safe_conversions.h"
  20. #include "base/strings/stringprintf.h"
  21. #include "base/strings/utf_string_conversions.h"
  22. #include "build/build_config.h"
  23. #include "minidump/minidump_context_writer.h"
  24. #include "minidump/minidump_writer_util.h"
  25. #include "package.h"
  26. #include "snapshot/cpu_context.h"
  27. #include "snapshot/process_snapshot.h"
  28. #include "snapshot/system_snapshot.h"
  29. #include "snapshot/thread_snapshot.h"
  30. #include "util/file/file_writer.h"
  31. #include "util/numeric/in_range_cast.h"
  32. #include "util/numeric/safe_assignment.h"
  33. #if BUILDFLAG(IS_MAC)
  34. #include <Availability.h>
  35. #elif BUILDFLAG(IS_ANDROID)
  36. #include <android/api-level.h>
  37. #endif
  38. namespace crashpad {
  39. namespace {
  40. uint32_t TimevalToRoundedSeconds(const timeval& tv) {
  41. uint32_t seconds =
  42. InRangeCast<uint32_t>(tv.tv_sec, std::numeric_limits<uint32_t>::max());
  43. constexpr int kMicrosecondsPerSecond = static_cast<int>(1E6);
  44. if (tv.tv_usec >= kMicrosecondsPerSecond / 2 &&
  45. seconds != std::numeric_limits<uint32_t>::max()) {
  46. ++seconds;
  47. }
  48. return seconds;
  49. }
  50. // For MINIDUMP_MISC_INFO_4::BuildString. dbghelp only places OS version
  51. // information here, but if a machine description is also available, this is the
  52. // only reasonable place in a minidump file to put it.
  53. std::string BuildString(const SystemSnapshot* system_snapshot) {
  54. std::string os_version_full = system_snapshot->OSVersionFull();
  55. std::string machine_description = system_snapshot->MachineDescription();
  56. if (!os_version_full.empty()) {
  57. if (!machine_description.empty()) {
  58. return base::StringPrintf(
  59. "%s; %s", os_version_full.c_str(), machine_description.c_str());
  60. }
  61. return os_version_full;
  62. }
  63. return machine_description;
  64. }
  65. #if BUILDFLAG(IS_MAC)
  66. // Converts the value of the __MAC_OS_X_VERSION_MIN_REQUIRED or
  67. // __MAC_OS_X_VERSION_MAX_ALLOWED macro from <Availability.h> to a number
  68. // identifying the macOS version that it represents, in the same format used by
  69. // MacOSVersionNumber(). For example, with an argument of __MAC_10_15, this
  70. // function will return 10'15'00, which is incidentally the same as __MAC_10_15.
  71. // With an argument of __MAC_10_9, this function will return 10'09'00, different
  72. // from __MAC_10_9, which is 10'9'0.
  73. int AvailabilityVersionToMacOSVersionNumber(int availability) {
  74. #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_10
  75. DCHECK_GE(availability, 10'0'0);
  76. // Until __MAC_10_10, the format is major * 1'0'0 + minor * 1'0 + bugfix.
  77. if (availability >= 10'0'0 && availability <= 10'9'9) {
  78. int minor = (availability / 1'0) % 1'0;
  79. int bugfix = availability % 1'0;
  80. return 10'00'00 + minor * 1'00 + bugfix;
  81. }
  82. #endif
  83. // Since __MAC_10_10, the format is major * 1'00'00 + minor * 1'00 + bugfix.
  84. DCHECK_GE(availability, 10'10'00);
  85. DCHECK_LE(availability, 99'99'99);
  86. return availability;
  87. }
  88. #endif // BUILDFLAG(IS_MAC)
  89. bool MaybeSetXStateData(const ProcessSnapshot* process_snapshot,
  90. XSTATE_CONFIG_FEATURE_MSC_INFO* xstate) {
  91. // Cannot set xstate data if there are no threads.
  92. auto threads = process_snapshot->Threads();
  93. if (threads.size() == 0)
  94. return false;
  95. // All threads should be the same as we request contexts in the same way.
  96. auto context = threads.at(0)->Context();
  97. // Only support AMD64.
  98. if (context->architecture != kCPUArchitectureX86_64)
  99. return false;
  100. // If no extended features, then we will just write the standard context.
  101. if (context->x86_64->xstate.enabled_features == 0)
  102. return false;
  103. xstate->SizeOfInfo = sizeof(*xstate);
  104. // Needs to match the size of the context we'll write or the dump is invalid,
  105. // so ask the first thread how large it will be.
  106. auto context_writer = MinidumpContextWriter::CreateFromSnapshot(context);
  107. xstate->ContextSize =
  108. static_cast<uint32_t>(context_writer->FreezeAndGetSizeOfObject());
  109. // Note: This isn't the same as xstateenabledfeatures!
  110. xstate->EnabledFeatures =
  111. context->x86_64->xstate.enabled_features | XSTATE_COMPACTION_ENABLE_MASK;
  112. // Note: if other XSAVE entries are to be supported they will be in order,
  113. // and may have different offsets depending on what is saved.
  114. if (context->x86_64->xstate.enabled_features & XSTATE_MASK_CET_U) {
  115. xstate->Features[XSTATE_CET_U].Offset = kXSaveAreaFirstOffset;
  116. xstate->Features[XSTATE_CET_U].Size = sizeof(MinidumpAMD64XSaveFormatCetU);
  117. }
  118. return true;
  119. }
  120. } // namespace
  121. namespace internal {
  122. // For MINIDUMP_MISC_INFO_4::DbgBldStr. dbghelp produces strings like
  123. // “dbghelp.i386,6.3.9600.16520” and “dbghelp.amd64,6.3.9600.16520”. Mimic that
  124. // format, and add the OS that wrote the minidump along with any relevant
  125. // platform-specific data describing the compilation environment.
  126. std::string MinidumpMiscInfoDebugBuildString() {
  127. // Caution: the minidump file format only has room for 39 UTF-16 code units
  128. // plus a UTF-16 NUL terminator. Don’t let strings get longer than this, or
  129. // they will be truncated and a message will be logged.
  130. #if BUILDFLAG(IS_MAC)
  131. static constexpr char kOS[] = "mac";
  132. #elif BUILDFLAG(IS_IOS)
  133. static constexpr char kOS[] = "ios";
  134. #elif BUILDFLAG(IS_ANDROID)
  135. static constexpr char kOS[] = "android";
  136. #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  137. static constexpr char kOS[] = "linux";
  138. #elif BUILDFLAG(IS_WIN)
  139. static constexpr char kOS[] = "win";
  140. #elif BUILDFLAG(IS_FUCHSIA)
  141. static constexpr char kOS[] = "fuchsia";
  142. #else
  143. #error define kOS for this operating system
  144. #endif
  145. #if defined(ARCH_CPU_X86)
  146. static constexpr char kCPU[] = "i386";
  147. #elif defined(ARCH_CPU_X86_64)
  148. static constexpr char kCPU[] = "amd64";
  149. #elif defined(ARCH_CPU_ARMEL)
  150. static constexpr char kCPU[] = "arm";
  151. #elif defined(ARCH_CPU_ARM64)
  152. static constexpr char kCPU[] = "arm64";
  153. #elif defined(ARCH_CPU_MIPSEL)
  154. static constexpr char kCPU[] = "mips";
  155. #elif defined(ARCH_CPU_MIPS64EL)
  156. static constexpr char kCPU[] = "mips64";
  157. #elif defined(ARCH_CPU_RISCV)
  158. static constexpr char kCPU[] = "riscv";
  159. #elif defined(ARCH_CPU_RISCV64)
  160. static constexpr char kCPU[] = "riscv64";
  161. #else
  162. #error define kCPU for this CPU
  163. #endif
  164. std::string debug_build_string = base::StringPrintf("%s.%s,%s,%s",
  165. PACKAGE_TARNAME,
  166. kCPU,
  167. PACKAGE_VERSION,
  168. kOS);
  169. #if BUILDFLAG(IS_MAC)
  170. debug_build_string += base::StringPrintf(
  171. ",%d,%d",
  172. AvailabilityVersionToMacOSVersionNumber(__MAC_OS_X_VERSION_MIN_REQUIRED),
  173. AvailabilityVersionToMacOSVersionNumber(__MAC_OS_X_VERSION_MAX_ALLOWED));
  174. #elif BUILDFLAG(IS_ANDROID)
  175. debug_build_string += base::StringPrintf(",%d", __ANDROID_API__);
  176. #endif
  177. return debug_build_string;
  178. }
  179. } // namespace internal
  180. MinidumpMiscInfoWriter::MinidumpMiscInfoWriter()
  181. : MinidumpStreamWriter(), misc_info_(), has_xstate_data_(false) {
  182. }
  183. MinidumpMiscInfoWriter::~MinidumpMiscInfoWriter() {
  184. }
  185. void MinidumpMiscInfoWriter::InitializeFromSnapshot(
  186. const ProcessSnapshot* process_snapshot) {
  187. DCHECK_EQ(state(), kStateMutable);
  188. DCHECK_EQ(misc_info_.Flags1, 0u);
  189. SetProcessID(InRangeCast<uint32_t>(process_snapshot->ProcessID(), 0));
  190. const SystemSnapshot* system_snapshot = process_snapshot->System();
  191. uint64_t current_hz;
  192. uint64_t max_hz;
  193. system_snapshot->CPUFrequency(&current_hz, &max_hz);
  194. constexpr uint32_t kHzPerMHz = static_cast<const uint32_t>(1E6);
  195. SetProcessorPowerInfo(
  196. InRangeCast<uint32_t>(current_hz / kHzPerMHz,
  197. std::numeric_limits<uint32_t>::max()),
  198. InRangeCast<uint32_t>(max_hz / kHzPerMHz,
  199. std::numeric_limits<uint32_t>::max()),
  200. 0,
  201. 0,
  202. 0);
  203. timeval start_time;
  204. process_snapshot->ProcessStartTime(&start_time);
  205. timeval user_time;
  206. timeval system_time;
  207. process_snapshot->ProcessCPUTimes(&user_time, &system_time);
  208. // Round the resource usage fields to the nearest second, because the minidump
  209. // format only has one-second resolution. The start_time field is truncated
  210. // instead of rounded so that the process uptime is reflected more accurately
  211. // when the start time is compared to the snapshot time in the
  212. // MINIDUMP_HEADER, which is also truncated, not rounded.
  213. uint32_t user_seconds = TimevalToRoundedSeconds(user_time);
  214. uint32_t system_seconds = TimevalToRoundedSeconds(system_time);
  215. SetProcessTimes(start_time.tv_sec, user_seconds, system_seconds);
  216. // This determines the system’s time zone, which may be different than the
  217. // process’ notion of the time zone.
  218. SystemSnapshot::DaylightSavingTimeStatus dst_status;
  219. int standard_offset_seconds;
  220. int daylight_offset_seconds;
  221. std::string standard_name;
  222. std::string daylight_name;
  223. system_snapshot->TimeZone(&dst_status,
  224. &standard_offset_seconds,
  225. &daylight_offset_seconds,
  226. &standard_name,
  227. &daylight_name);
  228. // standard_offset_seconds is seconds east of UTC, but the minidump file wants
  229. // minutes west of UTC. daylight_offset_seconds is also seconds east of UTC,
  230. // but the minidump file wants minutes west of the standard offset. The empty
  231. // ({}) arguments are for the transition times in and out of daylight saving
  232. // time. These are not determined because no API exists to do so, and the
  233. // transition times may vary from year to year.
  234. SetTimeZone(dst_status,
  235. standard_offset_seconds / -60,
  236. standard_name,
  237. {},
  238. 0,
  239. daylight_name,
  240. {},
  241. (standard_offset_seconds - daylight_offset_seconds) / 60);
  242. SetBuildString(BuildString(system_snapshot),
  243. internal::MinidumpMiscInfoDebugBuildString());
  244. XSTATE_CONFIG_FEATURE_MSC_INFO xstate{};
  245. if (MaybeSetXStateData(process_snapshot, &xstate)) {
  246. SetXStateData(xstate);
  247. }
  248. }
  249. void MinidumpMiscInfoWriter::SetProcessID(uint32_t process_id) {
  250. DCHECK_EQ(state(), kStateMutable);
  251. misc_info_.ProcessId = process_id;
  252. misc_info_.Flags1 |= MINIDUMP_MISC1_PROCESS_ID;
  253. }
  254. void MinidumpMiscInfoWriter::SetProcessTimes(time_t process_create_time,
  255. uint32_t process_user_time,
  256. uint32_t process_kernel_time) {
  257. DCHECK_EQ(state(), kStateMutable);
  258. internal::MinidumpWriterUtil::AssignTimeT(&misc_info_.ProcessCreateTime,
  259. process_create_time);
  260. misc_info_.ProcessUserTime = process_user_time;
  261. misc_info_.ProcessKernelTime = process_kernel_time;
  262. misc_info_.Flags1 |= MINIDUMP_MISC1_PROCESS_TIMES;
  263. }
  264. void MinidumpMiscInfoWriter::SetProcessorPowerInfo(
  265. uint32_t processor_max_mhz,
  266. uint32_t processor_current_mhz,
  267. uint32_t processor_mhz_limit,
  268. uint32_t processor_max_idle_state,
  269. uint32_t processor_current_idle_state) {
  270. DCHECK_EQ(state(), kStateMutable);
  271. misc_info_.ProcessorMaxMhz = processor_max_mhz;
  272. misc_info_.ProcessorCurrentMhz = processor_current_mhz;
  273. misc_info_.ProcessorMhzLimit = processor_mhz_limit;
  274. misc_info_.ProcessorMaxIdleState = processor_max_idle_state;
  275. misc_info_.ProcessorCurrentIdleState = processor_current_idle_state;
  276. misc_info_.Flags1 |= MINIDUMP_MISC1_PROCESSOR_POWER_INFO;
  277. }
  278. void MinidumpMiscInfoWriter::SetProcessIntegrityLevel(
  279. uint32_t process_integrity_level) {
  280. DCHECK_EQ(state(), kStateMutable);
  281. misc_info_.ProcessIntegrityLevel = process_integrity_level;
  282. misc_info_.Flags1 |= MINIDUMP_MISC3_PROCESS_INTEGRITY;
  283. }
  284. void MinidumpMiscInfoWriter::SetProcessExecuteFlags(
  285. uint32_t process_execute_flags) {
  286. DCHECK_EQ(state(), kStateMutable);
  287. misc_info_.ProcessExecuteFlags = process_execute_flags;
  288. misc_info_.Flags1 |= MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS;
  289. }
  290. void MinidumpMiscInfoWriter::SetProtectedProcess(uint32_t protected_process) {
  291. DCHECK_EQ(state(), kStateMutable);
  292. misc_info_.ProtectedProcess = protected_process;
  293. misc_info_.Flags1 |= MINIDUMP_MISC3_PROTECTED_PROCESS;
  294. }
  295. void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id,
  296. int32_t bias,
  297. const std::string& standard_name,
  298. const SYSTEMTIME& standard_date,
  299. int32_t standard_bias,
  300. const std::string& daylight_name,
  301. const SYSTEMTIME& daylight_date,
  302. int32_t daylight_bias) {
  303. DCHECK_EQ(state(), kStateMutable);
  304. misc_info_.TimeZoneId = time_zone_id;
  305. misc_info_.TimeZone.Bias = bias;
  306. internal::MinidumpWriterUtil::AssignUTF8ToUTF16(
  307. AsU16CStr(misc_info_.TimeZone.StandardName),
  308. std::size(misc_info_.TimeZone.StandardName),
  309. standard_name);
  310. misc_info_.TimeZone.StandardDate = standard_date;
  311. misc_info_.TimeZone.StandardBias = standard_bias;
  312. internal::MinidumpWriterUtil::AssignUTF8ToUTF16(
  313. AsU16CStr(misc_info_.TimeZone.DaylightName),
  314. std::size(misc_info_.TimeZone.DaylightName),
  315. daylight_name);
  316. misc_info_.TimeZone.DaylightDate = daylight_date;
  317. misc_info_.TimeZone.DaylightBias = daylight_bias;
  318. misc_info_.Flags1 |= MINIDUMP_MISC3_TIMEZONE;
  319. }
  320. void MinidumpMiscInfoWriter::SetBuildString(
  321. const std::string& build_string,
  322. const std::string& debug_build_string) {
  323. DCHECK_EQ(state(), kStateMutable);
  324. misc_info_.Flags1 |= MINIDUMP_MISC4_BUILDSTRING;
  325. internal::MinidumpWriterUtil::AssignUTF8ToUTF16(
  326. AsU16CStr(misc_info_.BuildString),
  327. std::size(misc_info_.BuildString),
  328. build_string);
  329. internal::MinidumpWriterUtil::AssignUTF8ToUTF16(
  330. AsU16CStr(misc_info_.DbgBldStr),
  331. std::size(misc_info_.DbgBldStr),
  332. debug_build_string);
  333. }
  334. void MinidumpMiscInfoWriter::SetXStateData(
  335. const XSTATE_CONFIG_FEATURE_MSC_INFO& xstate_data) {
  336. DCHECK_EQ(state(), kStateMutable);
  337. misc_info_.XStateData = xstate_data;
  338. has_xstate_data_ = true;
  339. }
  340. bool MinidumpMiscInfoWriter::HasXStateData() const {
  341. return has_xstate_data_;
  342. }
  343. void MinidumpMiscInfoWriter::SetProcessCookie(uint32_t process_cookie) {
  344. DCHECK_EQ(state(), kStateMutable);
  345. misc_info_.ProcessCookie = process_cookie;
  346. misc_info_.Flags1 |= MINIDUMP_MISC5_PROCESS_COOKIE;
  347. }
  348. bool MinidumpMiscInfoWriter::Freeze() {
  349. DCHECK_EQ(state(), kStateMutable);
  350. if (!MinidumpStreamWriter::Freeze()) {
  351. return false;
  352. }
  353. size_t size = CalculateSizeOfObjectFromFlags();
  354. if (!AssignIfInRange(&misc_info_.SizeOfInfo, size)) {
  355. LOG(ERROR) << "size " << size << " out of range";
  356. return false;
  357. }
  358. return true;
  359. }
  360. size_t MinidumpMiscInfoWriter::SizeOfObject() {
  361. DCHECK_GE(state(), kStateFrozen);
  362. return CalculateSizeOfObjectFromFlags();
  363. }
  364. bool MinidumpMiscInfoWriter::WriteObject(FileWriterInterface* file_writer) {
  365. DCHECK_EQ(state(), kStateWritable);
  366. return file_writer->Write(&misc_info_, CalculateSizeOfObjectFromFlags());
  367. }
  368. MinidumpStreamType MinidumpMiscInfoWriter::StreamType() const {
  369. return kMinidumpStreamTypeMiscInfo;
  370. }
  371. size_t MinidumpMiscInfoWriter::CalculateSizeOfObjectFromFlags() const {
  372. DCHECK_GE(state(), kStateFrozen);
  373. if (has_xstate_data_ || (misc_info_.Flags1 & MINIDUMP_MISC5_PROCESS_COOKIE)) {
  374. return sizeof(MINIDUMP_MISC_INFO_5);
  375. }
  376. if (misc_info_.Flags1 & MINIDUMP_MISC4_BUILDSTRING) {
  377. return sizeof(MINIDUMP_MISC_INFO_4);
  378. }
  379. if (misc_info_.Flags1 &
  380. (MINIDUMP_MISC3_PROCESS_INTEGRITY | MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS |
  381. MINIDUMP_MISC3_TIMEZONE | MINIDUMP_MISC3_PROTECTED_PROCESS)) {
  382. return sizeof(MINIDUMP_MISC_INFO_3);
  383. }
  384. if (misc_info_.Flags1 & MINIDUMP_MISC1_PROCESSOR_POWER_INFO) {
  385. return sizeof(MINIDUMP_MISC_INFO_2);
  386. }
  387. return sizeof(MINIDUMP_MISC_INFO);
  388. }
  389. } // namespace crashpad