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