exception_snapshot_linux.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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/exception_snapshot_linux.h"
  15. #include <signal.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 "snapshot/linux/process_reader_linux.h"
  20. #include "snapshot/linux/signal_context.h"
  21. #include "util/linux/traits.h"
  22. #include "util/misc/reinterpret_bytes.h"
  23. #include "util/numeric/safe_assignment.h"
  24. #include "util/posix/signals.h"
  25. namespace crashpad {
  26. namespace internal {
  27. ExceptionSnapshotLinux::ExceptionSnapshotLinux()
  28. : ExceptionSnapshot(),
  29. context_union_(),
  30. context_(),
  31. codes_(),
  32. thread_id_(0),
  33. exception_address_(0),
  34. signal_number_(0),
  35. signal_code_(0),
  36. initialized_() {}
  37. ExceptionSnapshotLinux::~ExceptionSnapshotLinux() {}
  38. #if defined(ARCH_CPU_X86_FAMILY)
  39. template <>
  40. bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
  41. ProcessReaderLinux* reader,
  42. LinuxVMAddress context_address) {
  43. UContext<ContextTraits32> ucontext;
  44. if (!reader->Memory()->Read(context_address, sizeof(ucontext), &ucontext)) {
  45. LOG(ERROR) << "Couldn't read ucontext";
  46. return false;
  47. }
  48. context_.architecture = kCPUArchitectureX86;
  49. context_.x86 = &context_union_.x86;
  50. if (!ucontext.mcontext.fpptr) {
  51. InitializeCPUContextX86_NoFloatingPoint(ucontext.mcontext.gprs,
  52. context_.x86);
  53. return true;
  54. }
  55. SignalFloatContext32 fprs;
  56. if (!reader->Memory()->Read(ucontext.mcontext.fpptr, sizeof(fprs), &fprs)) {
  57. LOG(ERROR) << "Couldn't read float context";
  58. return false;
  59. }
  60. if (fprs.magic == X86_FXSR_MAGIC) {
  61. InitializeCPUContextX86_NoFloatingPoint(ucontext.mcontext.gprs,
  62. context_.x86);
  63. if (!reader->Memory()->Read(
  64. ucontext.mcontext.fpptr + offsetof(SignalFloatContext32, fxsave),
  65. sizeof(CPUContextX86::Fxsave),
  66. &context_.x86->fxsave)) {
  67. LOG(ERROR) << "Couldn't read fxsave";
  68. return false;
  69. }
  70. } else if (fprs.magic == 0xffff) {
  71. InitializeCPUContextX86(ucontext.mcontext.gprs, fprs, context_.x86);
  72. } else {
  73. LOG(ERROR) << "unexpected magic 0x" << std::hex << fprs.magic;
  74. return false;
  75. }
  76. return true;
  77. }
  78. template <>
  79. bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
  80. ProcessReaderLinux* reader,
  81. LinuxVMAddress context_address) {
  82. UContext<ContextTraits64> ucontext;
  83. if (!reader->Memory()->Read(context_address, sizeof(ucontext), &ucontext)) {
  84. LOG(ERROR) << "Couldn't read ucontext";
  85. return false;
  86. }
  87. context_.architecture = kCPUArchitectureX86_64;
  88. context_.x86_64 = &context_union_.x86_64;
  89. if (!ucontext.mcontext.fpptr) {
  90. InitializeCPUContextX86_64_NoFloatingPoint(ucontext.mcontext.gprs,
  91. context_.x86_64);
  92. return true;
  93. }
  94. SignalFloatContext64 fprs;
  95. if (!reader->Memory()->Read(ucontext.mcontext.fpptr, sizeof(fprs), &fprs)) {
  96. LOG(ERROR) << "Couldn't read float context";
  97. return false;
  98. }
  99. InitializeCPUContextX86_64(ucontext.mcontext.gprs, fprs, context_.x86_64);
  100. return true;
  101. }
  102. #elif defined(ARCH_CPU_ARM_FAMILY)
  103. template <>
  104. bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
  105. ProcessReaderLinux* reader,
  106. LinuxVMAddress context_address) {
  107. context_.architecture = kCPUArchitectureARM;
  108. context_.arm = &context_union_.arm;
  109. CPUContextARM* dest_context = context_.arm;
  110. const ProcessMemory* memory = reader->Memory();
  111. LinuxVMAddress gprs_address =
  112. context_address + offsetof(UContext<ContextTraits32>, mcontext32) +
  113. offsetof(ContextTraits32::MContext32, gprs);
  114. SignalThreadContext32 thread_context;
  115. if (!memory->Read(gprs_address, sizeof(thread_context), &thread_context)) {
  116. LOG(ERROR) << "Couldn't read gprs";
  117. return false;
  118. }
  119. InitializeCPUContextARM_NoFloatingPoint(thread_context, dest_context);
  120. LinuxVMAddress reserved_address =
  121. context_address + offsetof(UContext<ContextTraits32>, reserved);
  122. if ((reserved_address & 7) != 0) {
  123. LOG(ERROR) << "invalid alignment 0x" << std::hex << reserved_address;
  124. return false;
  125. }
  126. constexpr VMSize kMaxContextSpace = 1024;
  127. ProcessMemoryRange range;
  128. if (!range.Initialize(memory, false, reserved_address, kMaxContextSpace)) {
  129. return false;
  130. }
  131. do {
  132. CoprocessorContextHead head;
  133. if (!range.Read(reserved_address, sizeof(head), &head)) {
  134. LOG(ERROR) << "missing context terminator";
  135. return false;
  136. }
  137. reserved_address += sizeof(head);
  138. switch (head.magic) {
  139. case VFP_MAGIC:
  140. if (head.size != sizeof(SignalVFPContext) + sizeof(head)) {
  141. LOG(ERROR) << "unexpected vfp context size " << head.size;
  142. return false;
  143. }
  144. static_assert(
  145. sizeof(SignalVFPContext::vfp) == sizeof(dest_context->vfp_regs),
  146. "vfp context size mismatch");
  147. if (!range.Read(reserved_address + offsetof(SignalVFPContext, vfp),
  148. sizeof(dest_context->vfp_regs),
  149. &dest_context->vfp_regs)) {
  150. LOG(ERROR) << "Couldn't read vfp";
  151. return false;
  152. }
  153. dest_context->have_vfp_regs = true;
  154. return true;
  155. case CRUNCH_MAGIC:
  156. case IWMMXT_MAGIC:
  157. case DUMMY_MAGIC:
  158. reserved_address += head.size - sizeof(head);
  159. continue;
  160. case 0:
  161. return true;
  162. default:
  163. LOG(ERROR) << "invalid magic number 0x" << std::hex << head.magic;
  164. return false;
  165. }
  166. } while (true);
  167. }
  168. template <>
  169. bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
  170. ProcessReaderLinux* reader,
  171. LinuxVMAddress context_address) {
  172. context_.architecture = kCPUArchitectureARM64;
  173. context_.arm64 = &context_union_.arm64;
  174. CPUContextARM64* dest_context = context_.arm64;
  175. const ProcessMemory* memory = reader->Memory();
  176. LinuxVMAddress gprs_address =
  177. context_address + offsetof(UContext<ContextTraits64>, mcontext64) +
  178. offsetof(ContextTraits64::MContext64, gprs);
  179. ThreadContext::t64_t thread_context;
  180. if (!memory->Read(gprs_address, sizeof(thread_context), &thread_context)) {
  181. LOG(ERROR) << "Couldn't read gprs";
  182. return false;
  183. }
  184. InitializeCPUContextARM64_NoFloatingPoint(thread_context, dest_context);
  185. LinuxVMAddress reserved_address =
  186. context_address + offsetof(UContext<ContextTraits64>, reserved);
  187. if ((reserved_address & 15) != 0) {
  188. LOG(ERROR) << "invalid alignment 0x" << std::hex << reserved_address;
  189. return false;
  190. }
  191. constexpr VMSize kMaxContextSpace = 4096;
  192. ProcessMemoryRange range;
  193. if (!range.Initialize(memory, true, reserved_address, kMaxContextSpace)) {
  194. return false;
  195. }
  196. do {
  197. CoprocessorContextHead head;
  198. if (!range.Read(reserved_address, sizeof(head), &head)) {
  199. LOG(ERROR) << "missing context terminator";
  200. return false;
  201. }
  202. reserved_address += sizeof(head);
  203. switch (head.magic) {
  204. case FPSIMD_MAGIC:
  205. if (head.size != sizeof(SignalFPSIMDContext) + sizeof(head)) {
  206. LOG(ERROR) << "unexpected fpsimd context size " << head.size;
  207. return false;
  208. }
  209. SignalFPSIMDContext fpsimd;
  210. if (!range.Read(reserved_address, sizeof(fpsimd), &fpsimd)) {
  211. LOG(ERROR) << "Couldn't read fpsimd " << head.size;
  212. return false;
  213. }
  214. InitializeCPUContextARM64_OnlyFPSIMD(fpsimd, dest_context);
  215. return true;
  216. case ESR_MAGIC:
  217. case EXTRA_MAGIC:
  218. reserved_address += head.size - sizeof(head);
  219. continue;
  220. case 0:
  221. LOG(WARNING) << "fpsimd not found";
  222. return true;
  223. default:
  224. LOG(ERROR) << "invalid magic number 0x" << std::hex << head.magic;
  225. return false;
  226. }
  227. } while (true);
  228. }
  229. #elif defined(ARCH_CPU_MIPS_FAMILY)
  230. template <typename Traits>
  231. static bool ReadContext(ProcessReaderLinux* reader,
  232. LinuxVMAddress context_address,
  233. typename Traits::CPUContext* dest_context) {
  234. const ProcessMemory* memory = reader->Memory();
  235. LinuxVMAddress gregs_address = context_address +
  236. offsetof(UContext<Traits>, mcontext) +
  237. offsetof(typename Traits::MContext, gregs);
  238. typename Traits::SignalThreadContext thread_context;
  239. if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) {
  240. LOG(ERROR) << "Couldn't read gregs";
  241. return false;
  242. }
  243. LinuxVMAddress fpregs_address = context_address +
  244. offsetof(UContext<Traits>, mcontext) +
  245. offsetof(typename Traits::MContext, fpregs);
  246. typename Traits::SignalFloatContext fp_context;
  247. if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) {
  248. LOG(ERROR) << "Couldn't read fpregs";
  249. return false;
  250. }
  251. InitializeCPUContextMIPS<Traits>(thread_context, fp_context, dest_context);
  252. return true;
  253. }
  254. template <>
  255. bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
  256. ProcessReaderLinux* reader,
  257. LinuxVMAddress context_address) {
  258. context_.architecture = kCPUArchitectureMIPSEL;
  259. context_.mipsel = &context_union_.mipsel;
  260. return internal::ReadContext<ContextTraits32>(
  261. reader, context_address, context_.mipsel);
  262. }
  263. template <>
  264. bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
  265. ProcessReaderLinux* reader,
  266. LinuxVMAddress context_address) {
  267. context_.architecture = kCPUArchitectureMIPS64EL;
  268. context_.mips64 = &context_union_.mips64;
  269. return internal::ReadContext<ContextTraits64>(
  270. reader, context_address, context_.mips64);
  271. }
  272. #elif defined(ARCH_CPU_RISCV_FAMILY)
  273. template <typename Traits>
  274. static bool ReadContext(ProcessReaderLinux* reader,
  275. LinuxVMAddress context_address,
  276. typename Traits::CPUContext* dest_context) {
  277. const ProcessMemory* memory = reader->Memory();
  278. LinuxVMAddress gregs_address = context_address +
  279. offsetof(UContext<Traits>, mcontext) +
  280. offsetof(typename Traits::MContext, gregs);
  281. typename Traits::SignalThreadContext thread_context;
  282. if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) {
  283. LOG(ERROR) << "Couldn't read gregs";
  284. return false;
  285. }
  286. LinuxVMAddress fpregs_address = context_address +
  287. offsetof(UContext<Traits>, mcontext) +
  288. offsetof(typename Traits::MContext, fpregs);
  289. typename Traits::SignalFloatContext fp_context;
  290. if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) {
  291. LOG(ERROR) << "Couldn't read fpregs";
  292. return false;
  293. }
  294. InitializeCPUContextRISCV<Traits>(thread_context, fp_context, dest_context);
  295. return true;
  296. }
  297. template <>
  298. bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
  299. ProcessReaderLinux* reader,
  300. LinuxVMAddress context_address) {
  301. context_.architecture = kCPUArchitectureRISCV;
  302. context_.riscv = &context_union_.riscv;
  303. return internal::ReadContext<ContextTraits32>(
  304. reader, context_address, context_.riscv);
  305. }
  306. template <>
  307. bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
  308. ProcessReaderLinux* reader,
  309. LinuxVMAddress context_address) {
  310. context_.architecture = kCPUArchitectureRISCV64;
  311. context_.riscv64 = &context_union_.riscv64;
  312. return internal::ReadContext<ContextTraits64>(
  313. reader, context_address, context_.riscv64);
  314. }
  315. #endif // ARCH_CPU_X86_FAMILY
  316. bool ExceptionSnapshotLinux::Initialize(
  317. ProcessReaderLinux* process_reader,
  318. LinuxVMAddress siginfo_address,
  319. LinuxVMAddress context_address,
  320. pid_t thread_id,
  321. uint32_t* gather_indirectly_referenced_memory_cap) {
  322. INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
  323. thread_id_ = thread_id;
  324. const ProcessReaderLinux::Thread* thread = nullptr;
  325. for (const auto& loop_thread : process_reader->Threads()) {
  326. if (thread_id == loop_thread.tid) {
  327. thread = &loop_thread;
  328. break;
  329. }
  330. }
  331. if (!thread) {
  332. // This is allowed until {ProcessReaderLinux::InitializeThreads()} is
  333. // improved to support target threads in the same thread group.
  334. LOG(WARNING) << "thread ID " << thread_id << " not found in process";
  335. }
  336. if (process_reader->Is64Bit()) {
  337. if (!ReadContext<ContextTraits64>(process_reader, context_address) ||
  338. !ReadSiginfo<Traits64>(process_reader, siginfo_address)) {
  339. return false;
  340. }
  341. } else {
  342. if (!ReadContext<ContextTraits32>(process_reader, context_address) ||
  343. !ReadSiginfo<Traits32>(process_reader, siginfo_address)) {
  344. return false;
  345. }
  346. }
  347. CaptureMemoryDelegateLinux capture_memory_delegate(
  348. process_reader,
  349. thread,
  350. &extra_memory_,
  351. gather_indirectly_referenced_memory_cap);
  352. CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
  353. INITIALIZATION_STATE_SET_VALID(initialized_);
  354. return true;
  355. }
  356. template <typename Traits>
  357. bool ExceptionSnapshotLinux::ReadSiginfo(ProcessReaderLinux* reader,
  358. LinuxVMAddress siginfo_address) {
  359. Siginfo<Traits> siginfo;
  360. if (!reader->Memory()->Read(siginfo_address, sizeof(siginfo), &siginfo)) {
  361. LOG(ERROR) << "Couldn't read siginfo";
  362. return false;
  363. }
  364. signal_number_ = siginfo.signo;
  365. signal_code_ = siginfo.code;
  366. uint64_t extra_code;
  367. #define PUSH_CODE(value) \
  368. do { \
  369. if (!ReinterpretBytes(value, &extra_code)) { \
  370. LOG(ERROR) << "bad code"; \
  371. return false; \
  372. } \
  373. codes_.push_back(extra_code); \
  374. } while (false)
  375. switch (siginfo.signo) {
  376. case SIGILL:
  377. case SIGFPE:
  378. case SIGSEGV:
  379. case SIGBUS:
  380. case SIGTRAP:
  381. exception_address_ = siginfo.address;
  382. break;
  383. case SIGPOLL: // SIGIO
  384. PUSH_CODE(siginfo.band);
  385. PUSH_CODE(siginfo.fd);
  386. break;
  387. case SIGSYS:
  388. exception_address_ = siginfo.call_address;
  389. PUSH_CODE(siginfo.syscall);
  390. PUSH_CODE(siginfo.arch);
  391. break;
  392. case SIGALRM:
  393. case SIGVTALRM:
  394. case SIGPROF:
  395. PUSH_CODE(siginfo.timerid);
  396. PUSH_CODE(siginfo.overrun);
  397. PUSH_CODE(siginfo.sigval.sigval);
  398. break;
  399. case SIGABRT:
  400. case SIGQUIT:
  401. case SIGXCPU:
  402. case SIGXFSZ:
  403. case SIGHUP:
  404. case SIGINT:
  405. case SIGPIPE:
  406. case SIGTERM:
  407. case SIGUSR1:
  408. case SIGUSR2:
  409. #if defined(SIGEMT)
  410. case SIGEMT:
  411. #endif // SIGEMT
  412. #if defined(SIGPWR)
  413. case SIGPWR:
  414. #endif // SIGPWR
  415. #if defined(SIGSTKFLT)
  416. case SIGSTKFLT:
  417. #endif // SIGSTKFLT
  418. PUSH_CODE(siginfo.pid);
  419. PUSH_CODE(siginfo.uid);
  420. PUSH_CODE(siginfo.sigval.sigval);
  421. break;
  422. case Signals::kSimulatedSigno:
  423. break;
  424. default:
  425. LOG(WARNING) << "Unhandled signal " << siginfo.signo;
  426. }
  427. return true;
  428. }
  429. const CPUContext* ExceptionSnapshotLinux::Context() const {
  430. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  431. return &context_;
  432. }
  433. uint64_t ExceptionSnapshotLinux::ThreadID() const {
  434. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  435. return thread_id_;
  436. }
  437. uint32_t ExceptionSnapshotLinux::Exception() const {
  438. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  439. return signal_number_;
  440. }
  441. uint32_t ExceptionSnapshotLinux::ExceptionInfo() const {
  442. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  443. return signal_code_;
  444. }
  445. uint64_t ExceptionSnapshotLinux::ExceptionAddress() const {
  446. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  447. return exception_address_;
  448. }
  449. const std::vector<uint64_t>& ExceptionSnapshotLinux::Codes() const {
  450. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  451. return codes_;
  452. }
  453. std::vector<const MemorySnapshot*> ExceptionSnapshotLinux::ExtraMemory() const {
  454. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  455. std::vector<const MemorySnapshot*> result;
  456. result.reserve(extra_memory_.size());
  457. for (const auto& em : extra_memory_) {
  458. result.push_back(em.get());
  459. }
  460. return result;
  461. }
  462. } // namespace internal
  463. } // namespace crashpad