thread_snapshot_linux.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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/thread_snapshot_linux.h"
  15. #include <sched.h>
  16. #include "base/logging.h"
  17. #include "snapshot/linux/capture_memory_delegate_linux.h"
  18. #include "snapshot/linux/cpu_context_linux.h"
  19. #include "util/misc/reinterpret_bytes.h"
  20. namespace crashpad {
  21. namespace internal {
  22. namespace {
  23. int ComputeThreadPriority(int static_priority,
  24. int sched_policy,
  25. int nice_value) {
  26. // Map Linux scheduling policy, static priority, and nice value into a
  27. // single int value.
  28. //
  29. // The possible policies in order of approximate priority (low to high) are
  30. // SCHED_IDLE
  31. // SCHED_BATCH
  32. // SCHED_OTHER
  33. // SCHED_RR
  34. // SCHED_FIFO
  35. //
  36. // static_priority is not used for OTHER, BATCH, or IDLE and should be 0.
  37. // For FIFO and RR, static_priority should range from 1 to 99 with 99 being
  38. // the highest priority.
  39. //
  40. // nice value ranges from -20 to 19, with -20 being highest priority
  41. enum class Policy : uint8_t {
  42. kUnknown = 0,
  43. kIdle,
  44. kBatch,
  45. kOther,
  46. kRR,
  47. kFIFO
  48. };
  49. struct LinuxPriority {
  50. #if defined(ARCH_CPU_LITTLE_ENDIAN)
  51. // nice values affect how dynamic priorities are updated, which only
  52. // matters for threads with the same static priority.
  53. uint8_t nice_value = 0;
  54. // The scheduling policy also affects how threads with the same static
  55. // priority are ordered, but has greater impact than nice value.
  56. Policy policy = Policy::kUnknown;
  57. // The static priority is the most significant in determining overall
  58. // priority.
  59. uint8_t static_priority = 0;
  60. // Put this in the most significant byte position to prevent negative
  61. // priorities.
  62. uint8_t unused = 0;
  63. #elif defined(ARCH_CPU_BIG_ENDIAN)
  64. uint8_t unused = 0;
  65. uint8_t static_priority = 0;
  66. Policy policy = Policy::kUnknown;
  67. uint8_t nice_value = 0;
  68. #endif // ARCH_CPU_LITTLE_ENDIAN
  69. };
  70. static_assert(sizeof(LinuxPriority) <= sizeof(int), "priority is too large");
  71. LinuxPriority prio;
  72. // Lower nice values have higher priority, so negate them and add 20 to put
  73. // them in the range 1-40 with 40 being highest priority.
  74. if (nice_value < -20 || nice_value > 19) {
  75. LOG(WARNING) << "invalid nice value " << nice_value;
  76. prio.nice_value = 0;
  77. } else {
  78. prio.nice_value = -1 * nice_value + 20;
  79. }
  80. switch (sched_policy) {
  81. case SCHED_IDLE:
  82. prio.policy = Policy::kIdle;
  83. break;
  84. case SCHED_BATCH:
  85. prio.policy = Policy::kBatch;
  86. break;
  87. case SCHED_OTHER:
  88. prio.policy = Policy::kOther;
  89. break;
  90. case SCHED_RR:
  91. prio.policy = Policy::kRR;
  92. break;
  93. case SCHED_FIFO:
  94. prio.policy = Policy::kFIFO;
  95. break;
  96. default:
  97. prio.policy = Policy::kUnknown;
  98. LOG(WARNING) << "Unknown scheduling policy " << sched_policy;
  99. }
  100. if (static_priority < 0 || static_priority > 99) {
  101. LOG(WARNING) << "invalid static priority " << static_priority;
  102. }
  103. prio.static_priority = static_priority;
  104. int priority;
  105. if (!ReinterpretBytes(prio, &priority)) {
  106. LOG(ERROR) << "Couldn't set priority";
  107. return -1;
  108. }
  109. return priority;
  110. }
  111. } // namespace
  112. ThreadSnapshotLinux::ThreadSnapshotLinux()
  113. : ThreadSnapshot(),
  114. context_union_(),
  115. context_(),
  116. stack_(),
  117. thread_specific_data_address_(0),
  118. thread_name_(),
  119. thread_id_(-1),
  120. priority_(-1),
  121. initialized_() {}
  122. ThreadSnapshotLinux::~ThreadSnapshotLinux() {}
  123. bool ThreadSnapshotLinux::Initialize(
  124. ProcessReaderLinux* process_reader,
  125. const ProcessReaderLinux::Thread& thread,
  126. uint32_t* gather_indirectly_referenced_memory_bytes_remaining) {
  127. INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
  128. #if defined(ARCH_CPU_X86_FAMILY)
  129. if (process_reader->Is64Bit()) {
  130. context_.architecture = kCPUArchitectureX86_64;
  131. context_.x86_64 = &context_union_.x86_64;
  132. InitializeCPUContextX86_64(thread.thread_info.thread_context.t64,
  133. thread.thread_info.float_context.f64,
  134. context_.x86_64);
  135. } else {
  136. context_.architecture = kCPUArchitectureX86;
  137. context_.x86 = &context_union_.x86;
  138. InitializeCPUContextX86(thread.thread_info.thread_context.t32,
  139. thread.thread_info.float_context.f32,
  140. context_.x86);
  141. }
  142. #elif defined(ARCH_CPU_ARM_FAMILY)
  143. if (process_reader->Is64Bit()) {
  144. context_.architecture = kCPUArchitectureARM64;
  145. context_.arm64 = &context_union_.arm64;
  146. InitializeCPUContextARM64(thread.thread_info.thread_context.t64,
  147. thread.thread_info.float_context.f64,
  148. context_.arm64);
  149. } else {
  150. context_.architecture = kCPUArchitectureARM;
  151. context_.arm = &context_union_.arm;
  152. InitializeCPUContextARM(thread.thread_info.thread_context.t32,
  153. thread.thread_info.float_context.f32,
  154. context_.arm);
  155. }
  156. #elif defined(ARCH_CPU_MIPS_FAMILY)
  157. if (process_reader->Is64Bit()) {
  158. context_.architecture = kCPUArchitectureMIPS64EL;
  159. context_.mips64 = &context_union_.mips64;
  160. InitializeCPUContextMIPS<ContextTraits64>(
  161. thread.thread_info.thread_context.t64,
  162. thread.thread_info.float_context.f64,
  163. context_.mips64);
  164. } else {
  165. context_.architecture = kCPUArchitectureMIPSEL;
  166. context_.mipsel = &context_union_.mipsel;
  167. InitializeCPUContextMIPS<ContextTraits32>(
  168. SignalThreadContext32(thread.thread_info.thread_context.t32),
  169. thread.thread_info.float_context.f32,
  170. context_.mipsel);
  171. }
  172. #elif defined(ARCH_CPU_RISCV_FAMILY)
  173. if (process_reader->Is64Bit()) {
  174. context_.architecture = kCPUArchitectureRISCV64;
  175. context_.riscv64 = &context_union_.riscv64;
  176. InitializeCPUContextRISCV<ContextTraits64>(
  177. thread.thread_info.thread_context.t64,
  178. thread.thread_info.float_context.f64,
  179. context_.riscv64);
  180. } else {
  181. context_.architecture = kCPUArchitectureRISCV;
  182. context_.riscv = &context_union_.riscv;
  183. InitializeCPUContextRISCV<ContextTraits32>(
  184. thread.thread_info.thread_context.t32,
  185. thread.thread_info.float_context.f32,
  186. context_.riscv);
  187. }
  188. #else
  189. #error Port.
  190. #endif
  191. stack_.Initialize(process_reader->Memory(),
  192. thread.stack_region_address,
  193. thread.stack_region_size);
  194. thread_specific_data_address_ =
  195. thread.thread_info.thread_specific_data_address;
  196. thread_name_ = thread.name;
  197. thread_id_ = thread.tid;
  198. priority_ =
  199. thread.have_priorities
  200. ? ComputeThreadPriority(
  201. thread.static_priority, thread.sched_policy, thread.nice_value)
  202. : -1;
  203. CaptureMemoryDelegateLinux capture_memory_delegate(
  204. process_reader,
  205. &thread,
  206. &pointed_to_memory_,
  207. gather_indirectly_referenced_memory_bytes_remaining);
  208. CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
  209. INITIALIZATION_STATE_SET_VALID(initialized_);
  210. return true;
  211. }
  212. const CPUContext* ThreadSnapshotLinux::Context() const {
  213. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  214. return &context_;
  215. }
  216. const MemorySnapshot* ThreadSnapshotLinux::Stack() const {
  217. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  218. return &stack_;
  219. }
  220. uint64_t ThreadSnapshotLinux::ThreadID() const {
  221. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  222. return thread_id_;
  223. }
  224. std::string ThreadSnapshotLinux::ThreadName() const {
  225. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  226. return thread_name_;
  227. }
  228. int ThreadSnapshotLinux::SuspendCount() const {
  229. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  230. return 0;
  231. }
  232. int ThreadSnapshotLinux::Priority() const {
  233. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  234. return priority_;
  235. }
  236. uint64_t ThreadSnapshotLinux::ThreadSpecificDataAddress() const {
  237. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  238. return thread_specific_data_address_;
  239. }
  240. std::vector<const MemorySnapshot*> ThreadSnapshotLinux::ExtraMemory() const {
  241. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  242. std::vector<const MemorySnapshot*> result;
  243. result.reserve(pointed_to_memory_.size());
  244. for (const auto& pointed_to_memory : pointed_to_memory_) {
  245. result.push_back(pointed_to_memory.get());
  246. }
  247. return result;
  248. }
  249. } // namespace internal
  250. } // namespace crashpad