system_snapshot_linux.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. // Copyright 2017 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 "snapshot/linux/system_snapshot_linux.h"
  15. #include <stddef.h>
  16. #include <sys/types.h>
  17. #include <sys/utsname.h>
  18. #include <algorithm>
  19. #include "base/files/file_path.h"
  20. #include "base/logging.h"
  21. #include "base/notreached.h"
  22. #include "base/strings/string_number_conversions.h"
  23. #include "base/strings/string_piece.h"
  24. #include "base/strings/stringprintf.h"
  25. #include "build/build_config.h"
  26. #include "snapshot/cpu_context.h"
  27. #include "snapshot/posix/timezone.h"
  28. #include "util/file/file_io.h"
  29. #include "util/numeric/in_range_cast.h"
  30. #include "util/string/split_string.h"
  31. #if BUILDFLAG(IS_ANDROID)
  32. #include <sys/system_properties.h>
  33. #endif
  34. namespace crashpad {
  35. namespace internal {
  36. namespace {
  37. bool ReadCPUsOnline(uint32_t* first_cpu, uint8_t* cpu_count) {
  38. std::string contents;
  39. if (!LoggingReadEntireFile(base::FilePath("/sys/devices/system/cpu/online"),
  40. &contents)) {
  41. return false;
  42. }
  43. if (contents.back() != '\n') {
  44. LOG(ERROR) << "format error";
  45. return false;
  46. }
  47. contents.pop_back();
  48. unsigned int count = 0;
  49. unsigned int first = 0;
  50. bool have_first = false;
  51. std::vector<std::string> ranges = SplitString(contents, ',');
  52. for (const auto& range : ranges) {
  53. std::string left, right;
  54. if (SplitStringFirst(range, '-', &left, &right)) {
  55. unsigned int start, end;
  56. if (!StringToUint(base::StringPiece(left), &start) ||
  57. !StringToUint(base::StringPiece(right), &end) || end <= start) {
  58. LOG(ERROR) << "format error: " << range;
  59. return false;
  60. }
  61. if (end <= start) {
  62. LOG(ERROR) << "format error";
  63. return false;
  64. }
  65. count += end - start + 1;
  66. if (!have_first) {
  67. first = start;
  68. have_first = true;
  69. }
  70. } else {
  71. unsigned int cpuno;
  72. if (!StringToUint(base::StringPiece(range), &cpuno)) {
  73. LOG(ERROR) << "format error";
  74. return false;
  75. }
  76. if (!have_first) {
  77. first = cpuno;
  78. have_first = true;
  79. }
  80. ++count;
  81. }
  82. }
  83. if (!have_first) {
  84. LOG(ERROR) << "no cpus online";
  85. return false;
  86. }
  87. *cpu_count = InRangeCast<uint8_t>(count, std::numeric_limits<uint8_t>::max());
  88. *first_cpu = first;
  89. return true;
  90. }
  91. bool ReadFreqFile(const std::string& filename, uint64_t* hz) {
  92. std::string contents;
  93. if (!LoggingReadEntireFile(base::FilePath(filename), &contents)) {
  94. return false;
  95. }
  96. if (contents.back() != '\n') {
  97. LOG(ERROR) << "format error";
  98. return false;
  99. }
  100. contents.pop_back();
  101. uint64_t khz;
  102. if (!base::StringToUint64(base::StringPiece(contents), &khz)) {
  103. LOG(ERROR) << "format error";
  104. return false;
  105. }
  106. *hz = khz * 1000;
  107. return true;
  108. }
  109. #if BUILDFLAG(IS_ANDROID)
  110. bool ReadProperty(const char* property, std::string* value) {
  111. char value_buffer[PROP_VALUE_MAX];
  112. int length = __system_property_get(property, value_buffer);
  113. if (length <= 0) {
  114. LOG(ERROR) << "Couldn't read property " << property;
  115. return false;
  116. }
  117. *value = value_buffer;
  118. return true;
  119. }
  120. #endif // BUILDFLAG(IS_ANDROID)
  121. } // namespace
  122. SystemSnapshotLinux::SystemSnapshotLinux()
  123. : SystemSnapshot(),
  124. os_version_full_(),
  125. os_version_build_(),
  126. process_reader_(nullptr),
  127. snapshot_time_(nullptr),
  128. #if defined(ARCH_CPU_X86_FAMILY)
  129. cpuid_(),
  130. #endif // ARCH_CPU_X86_FAMILY
  131. os_version_major_(-1),
  132. os_version_minor_(-1),
  133. os_version_bugfix_(-1),
  134. target_cpu_(0),
  135. cpu_count_(0),
  136. initialized_() {
  137. }
  138. SystemSnapshotLinux::~SystemSnapshotLinux() {}
  139. void SystemSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
  140. const timeval* snapshot_time) {
  141. INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
  142. process_reader_ = process_reader;
  143. snapshot_time_ = snapshot_time;
  144. #if BUILDFLAG(IS_ANDROID)
  145. std::string build_string;
  146. if (ReadProperty("ro.build.fingerprint", &build_string)) {
  147. os_version_build_ = build_string;
  148. os_version_full_ = build_string;
  149. }
  150. #endif // BUILDFLAG(IS_ANDROID)
  151. utsname uts;
  152. if (uname(&uts) != 0) {
  153. PLOG(WARNING) << "uname";
  154. } else {
  155. if (!os_version_full_.empty()) {
  156. os_version_full_.push_back(' ');
  157. }
  158. os_version_full_ += base::StringPrintf(
  159. "%s %s %s %s", uts.sysname, uts.release, uts.version, uts.machine);
  160. }
  161. ReadKernelVersion(uts.release);
  162. if (!os_version_build_.empty()) {
  163. os_version_build_.push_back(' ');
  164. }
  165. os_version_build_ += uts.version;
  166. os_version_build_.push_back(' ');
  167. os_version_build_ += uts.machine;
  168. if (!ReadCPUsOnline(&target_cpu_, &cpu_count_)) {
  169. target_cpu_ = 0;
  170. cpu_count_ = 0;
  171. }
  172. INITIALIZATION_STATE_SET_VALID(initialized_);
  173. }
  174. CPUArchitecture SystemSnapshotLinux::GetCPUArchitecture() const {
  175. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  176. #if defined(ARCH_CPU_X86_FAMILY)
  177. return process_reader_->Is64Bit() ? kCPUArchitectureX86_64
  178. : kCPUArchitectureX86;
  179. #elif defined(ARCH_CPU_ARM_FAMILY)
  180. return process_reader_->Is64Bit() ? kCPUArchitectureARM64
  181. : kCPUArchitectureARM;
  182. #elif defined(ARCH_CPU_MIPS_FAMILY)
  183. return process_reader_->Is64Bit() ? kCPUArchitectureMIPS64EL
  184. : kCPUArchitectureMIPSEL;
  185. #elif defined(ARCH_CPU_RISCV_FAMILY)
  186. return process_reader_->Is64Bit() ? kCPUArchitectureRISCV64
  187. : kCPUArchitectureRISCV;
  188. #else
  189. #error port to your architecture
  190. #endif
  191. }
  192. uint32_t SystemSnapshotLinux::CPURevision() const {
  193. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  194. #if defined(ARCH_CPU_X86_FAMILY)
  195. return cpuid_.Revision();
  196. #elif defined(ARCH_CPU_ARM_FAMILY)
  197. // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
  198. return 0;
  199. #elif defined(ARCH_CPU_MIPS_FAMILY)
  200. // Not implementable on MIPS
  201. return 0;
  202. #elif defined(ARCH_CPU_RISCV_FAMILY)
  203. // Not implementable on RISCV
  204. return 0;
  205. #else
  206. #error port to your architecture
  207. #endif
  208. }
  209. uint8_t SystemSnapshotLinux::CPUCount() const {
  210. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  211. return cpu_count_;
  212. }
  213. std::string SystemSnapshotLinux::CPUVendor() const {
  214. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  215. #if defined(ARCH_CPU_X86_FAMILY)
  216. return cpuid_.Vendor();
  217. #elif defined(ARCH_CPU_ARM_FAMILY)
  218. // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
  219. return std::string();
  220. #elif defined(ARCH_CPU_MIPS_FAMILY)
  221. // Not implementable on MIPS
  222. return std::string();
  223. #elif defined(ARCH_CPU_RISCV_FAMILY)
  224. // Not implementable on RISCV
  225. return std::string();
  226. #else
  227. #error port to your architecture
  228. #endif
  229. }
  230. void SystemSnapshotLinux::CPUFrequency(uint64_t* current_hz,
  231. uint64_t* max_hz) const {
  232. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  233. *current_hz = 0;
  234. *max_hz = 0;
  235. ReadFreqFile(base::StringPrintf(
  236. "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq",
  237. target_cpu_),
  238. current_hz);
  239. ReadFreqFile(base::StringPrintf(
  240. "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq",
  241. target_cpu_),
  242. max_hz);
  243. }
  244. uint32_t SystemSnapshotLinux::CPUX86Signature() const {
  245. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  246. #if defined(ARCH_CPU_X86_FAMILY)
  247. return cpuid_.Signature();
  248. #else
  249. NOTREACHED();
  250. return 0;
  251. #endif
  252. }
  253. uint64_t SystemSnapshotLinux::CPUX86Features() const {
  254. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  255. #if defined(ARCH_CPU_X86_FAMILY)
  256. return cpuid_.Features();
  257. #else
  258. NOTREACHED();
  259. return 0;
  260. #endif
  261. }
  262. uint64_t SystemSnapshotLinux::CPUX86ExtendedFeatures() const {
  263. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  264. #if defined(ARCH_CPU_X86_FAMILY)
  265. return cpuid_.ExtendedFeatures();
  266. #else
  267. NOTREACHED();
  268. return 0;
  269. #endif
  270. }
  271. uint32_t SystemSnapshotLinux::CPUX86Leaf7Features() const {
  272. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  273. #if defined(ARCH_CPU_X86_FAMILY)
  274. return cpuid_.Leaf7Features();
  275. #else
  276. NOTREACHED();
  277. return 0;
  278. #endif
  279. }
  280. bool SystemSnapshotLinux::CPUX86SupportsDAZ() const {
  281. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  282. #if defined(ARCH_CPU_X86_FAMILY)
  283. return cpuid_.SupportsDAZ();
  284. #else
  285. NOTREACHED();
  286. return false;
  287. #endif // ARCH_CPU_X86_FMAILY
  288. }
  289. SystemSnapshot::OperatingSystem SystemSnapshotLinux::GetOperatingSystem()
  290. const {
  291. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  292. #if BUILDFLAG(IS_ANDROID)
  293. return kOperatingSystemAndroid;
  294. #else
  295. return kOperatingSystemLinux;
  296. #endif // BUILDFLAG(IS_ANDROID)
  297. }
  298. bool SystemSnapshotLinux::OSServer() const {
  299. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  300. return false;
  301. }
  302. void SystemSnapshotLinux::OSVersion(int* major,
  303. int* minor,
  304. int* bugfix,
  305. std::string* build) const {
  306. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  307. *major = os_version_major_;
  308. *minor = os_version_minor_;
  309. *bugfix = os_version_bugfix_;
  310. build->assign(os_version_build_);
  311. }
  312. std::string SystemSnapshotLinux::OSVersionFull() const {
  313. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  314. return os_version_full_;
  315. }
  316. std::string SystemSnapshotLinux::MachineDescription() const {
  317. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  318. #if BUILDFLAG(IS_ANDROID)
  319. std::string description;
  320. std::string prop;
  321. if (ReadProperty("ro.product.model", &prop)) {
  322. description += prop;
  323. }
  324. if (ReadProperty("ro.product.board", &prop)) {
  325. if (!description.empty()) {
  326. description.push_back(' ');
  327. }
  328. description += prop;
  329. }
  330. return description;
  331. #else
  332. return std::string();
  333. #endif // BUILDFLAG(IS_ANDROID)
  334. }
  335. bool SystemSnapshotLinux::NXEnabled() const {
  336. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  337. #if defined(ARCH_CPU_X86_FAMILY)
  338. return cpuid_.NXEnabled();
  339. #elif defined(ARCH_CPU_ARM_FAMILY)
  340. // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
  341. return false;
  342. #elif defined(ARCH_CPU_MIPS_FAMILY)
  343. // Not implementable on MIPS
  344. return false;
  345. #elif defined(ARCH_CPU_RISCV_FAMILY)
  346. // Not implementable on RISCV
  347. return false;
  348. #else
  349. #error Port.
  350. #endif // ARCH_CPU_X86_FAMILY
  351. }
  352. void SystemSnapshotLinux::TimeZone(DaylightSavingTimeStatus* dst_status,
  353. int* standard_offset_seconds,
  354. int* daylight_offset_seconds,
  355. std::string* standard_name,
  356. std::string* daylight_name) const {
  357. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  358. internal::TimeZone(*snapshot_time_,
  359. dst_status,
  360. standard_offset_seconds,
  361. daylight_offset_seconds,
  362. standard_name,
  363. daylight_name);
  364. }
  365. void SystemSnapshotLinux::ReadKernelVersion(const std::string& version_string) {
  366. std::vector<std::string> versions = SplitString(version_string, '.');
  367. if (versions.size() < 3) {
  368. LOG(WARNING) << "format error";
  369. return;
  370. }
  371. if (!StringToInt(base::StringPiece(versions[0]), &os_version_major_)) {
  372. LOG(WARNING) << "no kernel version";
  373. return;
  374. }
  375. DCHECK_GE(os_version_major_, 3);
  376. if (!StringToInt(base::StringPiece(versions[1]), &os_version_minor_)) {
  377. LOG(WARNING) << "no major revision";
  378. return;
  379. }
  380. DCHECK_GE(os_version_minor_, 0);
  381. size_t minor_rev_end = versions[2].find_first_not_of("0123456789");
  382. if (minor_rev_end == std::string::npos) {
  383. minor_rev_end = versions[2].size();
  384. }
  385. if (!StringToInt(base::StringPiece(versions[2].c_str(), minor_rev_end),
  386. &os_version_bugfix_)) {
  387. LOG(WARNING) << "no minor revision";
  388. return;
  389. }
  390. DCHECK_GE(os_version_bugfix_, 0);
  391. if (!os_version_build_.empty()) {
  392. os_version_build_.push_back(' ');
  393. }
  394. os_version_build_ += versions[2].substr(minor_rev_end);
  395. }
  396. } // namespace internal
  397. } // namespace crashpad