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