[Tizen] Add a library to retrieve memory regions for a coredump
[platform/upstream/coreclr.git] / src / debug / createdump / threadinfo.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #include "createdump.h"
6 #include <asm/ptrace.h>
7
8 #if defined(__aarch64__)
9 // See src/pal/src/include/pal/context.h
10 #define MCREG_Fp(mc)      ((mc).regs[29])
11 #define MCREG_Lr(mc)      ((mc).regs[30])
12 #define MCREG_Sp(mc)      ((mc).sp)
13 #define MCREG_Pc(mc)      ((mc).pc)
14 #define MCREG_Cpsr(mc)    ((mc).pstate)
15 #endif
16
17 #ifndef THUMB_CODE
18 #define THUMB_CODE 1
19 #endif
20
21 #ifndef __GLIBC__
22 typedef int __ptrace_request;
23 #endif
24
25 #define FPREG_ErrorOffset(fpregs) *(DWORD*)&((fpregs).rip)
26 #define FPREG_ErrorSelector(fpregs) *(((WORD*)&((fpregs).rip)) + 2)
27 #define FPREG_DataOffset(fpregs) *(DWORD*)&((fpregs).rdp)
28 #define FPREG_DataSelector(fpregs) *(((WORD*)&((fpregs).rdp)) + 2)
29
30 extern CrashInfo* g_crashInfo;
31
32 ThreadInfo::ThreadInfo(pid_t tid) :
33     m_tid(tid)
34 {
35 }
36
37 ThreadInfo::~ThreadInfo()
38 {
39 }
40
41 bool
42 ThreadInfo::Initialize(ICLRDataTarget* pDataTarget)
43 {
44     if (!CrashInfo::GetStatus(m_tid, &m_ppid, &m_tgid, nullptr)) 
45     {
46         return false;
47     }
48     if (pDataTarget != nullptr)
49     {
50         if (!GetRegistersWithDataTarget(pDataTarget))
51         {
52             return false;
53         }
54     }
55     else {
56         if (!GetRegistersWithPTrace())
57         {
58             return false;
59         }
60     }
61
62 #if defined(__aarch64__)
63     TRACE("Thread %04x PC %016llx SP %016llx\n", m_tid, (unsigned long long)MCREG_Pc(m_gpRegisters), (unsigned long long)MCREG_Sp(m_gpRegisters));
64 #elif defined(__arm__)
65     TRACE("Thread %04x PC %08lx SP %08lx\n", m_tid, (unsigned long)m_gpRegisters.ARM_pc, (unsigned long)m_gpRegisters.ARM_sp);
66 #elif defined(__x86_64__)
67     TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, (unsigned long long)m_gpRegisters.rip, (unsigned long long)m_gpRegisters.rsp);
68 #elif defined(__i386__)
69     TRACE("Thread %04x EIP %016lx ESP %016lx\n", m_tid, (unsigned long)m_gpRegisters.eip, (unsigned long)m_gpRegisters.esp);
70 #else
71 #error "Unsupported architecture"
72 #endif
73     return true;
74 }
75
76 void
77 ThreadInfo::ResumeThread()
78 {
79     if (ptrace(PTRACE_DETACH, m_tid, nullptr, nullptr) != -1)
80     {
81         int waitStatus;
82         waitpid(m_tid, &waitStatus, __WALL);
83     }
84 }
85
86 // Helper for UnwindNativeFrames
87 static void
88 GetFrameLocation(CONTEXT* pContext, uint64_t* ip, uint64_t* sp)
89 {
90 #if defined(__x86_64__)
91     *ip = pContext->Rip;
92     *sp = pContext->Rsp;
93 #elif defined(__i386__)
94     *ip = pContext->Eip;
95     *sp = pContext->Esp;
96 #elif defined(__aarch64__)
97     *ip = pContext->Pc;
98     *sp = pContext->Sp;
99 #elif defined(__arm__)
100     *ip = pContext->Pc & ~THUMB_CODE;
101     *sp = pContext->Sp;
102 #endif
103 }
104
105 // Helper for UnwindNativeFrames
106 static BOOL 
107 ReadMemoryAdapter(PVOID address, PVOID buffer, SIZE_T size)
108 {
109     return g_crashInfo->ReadMemory(address, buffer, size);
110 }
111
112 void
113 ThreadInfo::UnwindNativeFrames(CrashInfo& crashInfo, CONTEXT* pContext)
114 {
115     uint64_t previousSp = 0;
116
117     // For each native frame
118     while (true)
119     {
120         uint64_t ip = 0, sp = 0;
121         GetFrameLocation(pContext, &ip, &sp);
122
123         TRACE("Unwind: sp %" PRIA PRIx64 " ip %" PRIA PRIx64 "\n", sp, ip);
124         if (ip == 0 || sp <= previousSp) {
125             break;
126         }
127
128         // Add two pages around the instruction pointer to the core dump
129         crashInfo.InsertMemoryRegion(ip - PAGE_SIZE, PAGE_SIZE * 2);
130
131         // Look up the ip address to get the module base address
132         uint64_t baseAddress = crashInfo.GetBaseAddress(ip);
133         if (baseAddress == 0) {
134             TRACE("Unwind: module base not found ip %" PRIA PRIx64 "\n", ip);
135             break;
136         }
137
138         // Unwind the native frame adding all the memory accessed to the 
139         // core dump via the read memory adapter.
140         if (!PAL_VirtualUnwindOutOfProc(pContext, nullptr, baseAddress, ReadMemoryAdapter)) {
141             TRACE("Unwind: PAL_VirtualUnwindOutOfProc returned false\n");
142             break;
143         }
144         previousSp = sp;
145     }
146 }
147
148 bool
149 ThreadInfo::UnwindThread(CrashInfo& crashInfo, IXCLRDataProcess* pClrDataProcess)
150 {
151     TRACE("Unwind: thread %04x\n", Tid());
152
153     // Get starting native context for the thread
154     CONTEXT context;
155     GetThreadContext(CONTEXT_ALL, &context);
156
157     // Unwind the native frames at the top of the stack
158     UnwindNativeFrames(crashInfo, &context);
159
160     if (pClrDataProcess != nullptr)
161     {
162         ReleaseHolder<IXCLRDataTask> pTask;
163         ReleaseHolder<IXCLRDataStackWalk> pStackwalk;
164
165         // Get the managed stack walker for this thread
166         if (SUCCEEDED(pClrDataProcess->GetTaskByOSThreadID(Tid(), &pTask)))
167         {
168             pTask->CreateStackWalk(
169                 CLRDATA_SIMPFRAME_UNRECOGNIZED |
170                 CLRDATA_SIMPFRAME_MANAGED_METHOD |
171                 CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE |
172                 CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE,
173                 &pStackwalk);
174         }
175
176         // For each managed frame (if any)
177         if (pStackwalk != nullptr)
178         {
179             TRACE("Unwind: managed frames\n");
180             do
181             {
182                 // Get the managed stack frame context
183                 if (pStackwalk->GetContext(CONTEXT_ALL, sizeof(context), nullptr, (BYTE *)&context) != S_OK) {
184                     TRACE("Unwind: stack walker GetContext FAILED\n");
185                     break;
186                 }
187
188                 // Unwind all the native frames after the managed frame
189                 UnwindNativeFrames(crashInfo, &context);
190
191             } while (pStackwalk->Next() == S_OK);
192         }
193     }
194
195     return true;
196 }
197
198 bool 
199 ThreadInfo::GetRegistersWithPTrace()
200 {
201 #if defined(__aarch64__)
202     struct iovec gpRegsVec = { &m_gpRegisters, sizeof(m_gpRegisters) };
203     if (ptrace((__ptrace_request)PTRACE_GETREGSET, m_tid, NT_PRSTATUS, &gpRegsVec) == -1)
204     {
205         fprintf(stderr, "ptrace(PTRACE_GETREGSET, %d, NT_PRSTATUS) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
206         return false;
207     }
208     assert(sizeof(m_gpRegisters) == gpRegsVec.iov_len);
209
210     struct iovec fpRegsVec = { &m_fpRegisters, sizeof(m_fpRegisters) };
211     if (ptrace((__ptrace_request)PTRACE_GETREGSET, m_tid, NT_FPREGSET, &fpRegsVec) == -1)
212     {
213         fprintf(stderr, "ptrace(PTRACE_GETREGSET, %d, NT_FPREGSET) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
214         return false;
215     }
216     assert(sizeof(m_fpRegisters) == fpRegsVec.iov_len);
217 #else
218     if (ptrace((__ptrace_request)PTRACE_GETREGS, m_tid, nullptr, &m_gpRegisters) == -1)
219     {
220         fprintf(stderr, "ptrace(GETREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
221         return false;
222     }
223     if (ptrace((__ptrace_request)PTRACE_GETFPREGS, m_tid, nullptr, &m_fpRegisters) == -1)
224     {
225         fprintf(stderr, "ptrace(GETFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
226         return false;
227     }
228 #if defined(__i386__)
229     if (ptrace((__ptrace_request)PTRACE_GETFPXREGS, m_tid, nullptr, &m_fpxRegisters) == -1)
230     {
231         fprintf(stderr, "ptrace(GETFPXREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
232         return false;
233     }
234 #elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__)
235
236 #if defined(ARM_VFPREGS_SIZE)
237     assert(sizeof(m_vfpRegisters) == ARM_VFPREGS_SIZE);
238 #endif
239
240     if (ptrace((__ptrace_request)PTRACE_GETVFPREGS, m_tid, nullptr, &m_vfpRegisters) == -1)
241     {
242         fprintf(stderr, "ptrace(PTRACE_GETVFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
243         return false;
244     }
245 #endif
246 #endif
247     return true;
248 }
249 void ThreadInfo::SetRegisters(elf_prstatus *prstatus)
250 {
251 #if defined(__x86_64__)
252     struct user_regs_struct *u_reg = (struct user_regs_struct *)&prstatus->pr_reg;
253     m_gpRegisters.rip = u_reg->rip;
254     m_gpRegisters.rbp = u_reg->rbp;
255     m_gpRegisters.rsp = u_reg->rsp;
256
257     m_gpRegisters.rax = u_reg->rax;
258     m_gpRegisters.rbx = u_reg->rbx;
259     m_gpRegisters.rcx = u_reg->rcx;
260     m_gpRegisters.rdx = u_reg->rdx;
261     m_gpRegisters.rsi = u_reg->rsi;
262     m_gpRegisters.rdi = u_reg->rdi;
263
264     m_gpRegisters.cs = u_reg->cs;
265     m_gpRegisters.gs = u_reg->gs;
266     m_gpRegisters.es = u_reg->es;
267     m_gpRegisters.fs = u_reg->fs;
268     m_gpRegisters.ds = u_reg->ds;
269     m_gpRegisters.ss = u_reg->ss;
270     m_gpRegisters.fs_base = u_reg->fs_base;
271     m_gpRegisters.gs_base = u_reg->gs_base;
272
273     m_gpRegisters.orig_rax = u_reg->orig_rax;
274
275     m_gpRegisters.r8 = u_reg->r8;
276     m_gpRegisters.r9 = u_reg->r9;
277     m_gpRegisters.r10 = u_reg->r10;
278     m_gpRegisters.r11 = u_reg->r11;
279     m_gpRegisters.r12 = u_reg->r12;
280     m_gpRegisters.r13 = u_reg->r13;
281     m_gpRegisters.r14 = u_reg->r14;
282     m_gpRegisters.r15 = u_reg->r15;
283
284     m_gpRegisters.eflags = u_reg->eflags;
285 #elif defined(__i386__)
286     struct user_regs_struct *u_reg = (struct user_regs_struct *)&prstatus->pr_reg;
287     m_gpRegisters.ebx = u_reg->ebx;
288     m_gpRegisters.ecx = u_reg->ecx;
289     m_gpRegisters.edx = u_reg->edx;
290     m_gpRegisters.esi = u_reg->esi;
291     m_gpRegisters.edi = u_reg->edi;
292     m_gpRegisters.ebp = u_reg->ebp;
293     m_gpRegisters.eax = u_reg->eax;
294     m_gpRegisters.xds = u_reg->xds;
295     m_gpRegisters.xes = u_reg->xes;
296     m_gpRegisters.xfs = u_reg->xfs;
297     m_gpRegisters.xgs = u_reg->xgs;
298     m_gpRegisters.orig_eax = u_reg->orig_eax;
299     m_gpRegisters.eip = u_reg->eip;
300     m_gpRegisters.xcs = u_reg->xcs;
301     m_gpRegisters.eflags = u_reg->eflags;
302     m_gpRegisters.esp = u_reg->esp;
303     m_gpRegisters.xss = u_reg->xss;
304 #elif defined(__arm__)
305
306 #define REGS_REGULAR_NUM 13
307 #define REG_FP 11
308 #define REG_IP 12
309 #define REG_SP 13
310 #define REG_LR 14
311 #define REG_PC 15
312 #define REG_SPSR 16
313     struct user_regs *u_reg = (struct user_regs *)&prstatus->pr_reg;
314     m_gpRegisters.ARM_sp = u_reg->uregs[REG_SP];
315     m_gpRegisters.ARM_lr = u_reg->uregs[REG_LR];
316     m_gpRegisters.ARM_pc = u_reg->uregs[REG_PC];
317     m_gpRegisters.ARM_cpsr = u_reg->uregs[REG_SPSR];
318
319     m_gpRegisters.ARM_r0 = u_reg->uregs[0];
320     m_gpRegisters.ARM_ORIG_r0 = u_reg->uregs[0];
321     m_gpRegisters.ARM_r1 = u_reg->uregs[1];
322     m_gpRegisters.ARM_r2 = u_reg->uregs[2];
323     m_gpRegisters.ARM_r3 = u_reg->uregs[3];
324     m_gpRegisters.ARM_r4 = u_reg->uregs[4];
325     m_gpRegisters.ARM_r5 = u_reg->uregs[5];
326     m_gpRegisters.ARM_r6 = u_reg->uregs[6];
327     m_gpRegisters.ARM_r7 = u_reg->uregs[7];
328     m_gpRegisters.ARM_r8 = u_reg->uregs[8];
329     m_gpRegisters.ARM_r9 = u_reg->uregs[9];
330     m_gpRegisters.ARM_r10 = u_reg->uregs[10];
331     m_gpRegisters.ARM_fp = u_reg->uregs[REG_FP];
332     m_gpRegisters.ARM_ip = u_reg->uregs[REG_IP];
333 #endif
334 }
335
336 bool 
337 ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* pDataTarget)
338 {
339     CONTEXT context;
340     context.ContextFlags = CONTEXT_ALL;
341     if (pDataTarget->GetThreadContext(m_tid, context.ContextFlags, sizeof(context), reinterpret_cast<PBYTE>(&context)) != S_OK)
342     {
343         return false;
344     }
345 #if defined(__x86_64__)
346     m_gpRegisters.rbp = context.Rbp;
347     m_gpRegisters.rip = context.Rip;
348     m_gpRegisters.cs = context.SegCs;
349     m_gpRegisters.eflags = context.EFlags;
350     m_gpRegisters.ss = context.SegSs;
351     m_gpRegisters.rsp = context.Rsp;
352     m_gpRegisters.rdi = context.Rdi;
353
354     m_gpRegisters.rsi = context.Rsi;
355     m_gpRegisters.rbx = context.Rbx;
356     m_gpRegisters.rdx = context.Rdx;
357     m_gpRegisters.rcx = context.Rcx;
358     m_gpRegisters.rax = context.Rax;
359     m_gpRegisters.orig_rax = context.Rax;
360     m_gpRegisters.r8 = context.R8;
361     m_gpRegisters.r9 = context.R9;
362     m_gpRegisters.r10 = context.R10;
363     m_gpRegisters.r11 = context.R11;
364     m_gpRegisters.r12 = context.R12;
365     m_gpRegisters.r13 = context.R13;
366     m_gpRegisters.r14 = context.R14;
367     m_gpRegisters.r15 = context.R15;
368
369     m_gpRegisters.ds = context.SegDs;
370     m_gpRegisters.es = context.SegEs;
371     m_gpRegisters.fs = context.SegFs;
372     m_gpRegisters.gs = context.SegGs;
373     m_gpRegisters.fs_base = 0;
374     m_gpRegisters.gs_base = 0;
375
376     m_fpRegisters.cwd = context.FltSave.ControlWord;
377     m_fpRegisters.swd = context.FltSave.StatusWord;
378     m_fpRegisters.ftw = context.FltSave.TagWord;
379     m_fpRegisters.fop = context.FltSave.ErrorOpcode;
380
381     FPREG_ErrorOffset(m_fpRegisters) = context.FltSave.ErrorOffset;
382     FPREG_ErrorSelector(m_fpRegisters) = context.FltSave.ErrorSelector;
383     FPREG_DataOffset(m_fpRegisters) = context.FltSave.DataOffset;
384     FPREG_DataSelector(m_fpRegisters) = context.FltSave.DataSelector;
385
386     m_fpRegisters.mxcsr = context.FltSave.MxCsr;
387     m_fpRegisters.mxcr_mask = context.FltSave.MxCsr_Mask;
388
389     assert(sizeof(context.FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space));
390     memcpy(m_fpRegisters.st_space, context.FltSave.FloatRegisters, sizeof(m_fpRegisters.st_space));
391
392     assert(sizeof(context.FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space));
393     memcpy(m_fpRegisters.xmm_space, context.FltSave.XmmRegisters, sizeof(m_fpRegisters.xmm_space));
394 #elif defined(__aarch64__)
395     // See MCREG maps in PAL's context.h
396     assert(sizeof(m_gpRegisters.regs) == (sizeof(context.X) + sizeof(context.Fp) + sizeof(context.Lr)));
397     memcpy(m_gpRegisters.regs, context.X, sizeof(context.X));
398     MCREG_Fp(m_gpRegisters) = context.Fp;
399     MCREG_Lr(m_gpRegisters) = context.Lr;
400     MCREG_Sp(m_gpRegisters) = context.Sp;
401     MCREG_Pc(m_gpRegisters) = context.Pc;
402     MCREG_Cpsr(m_gpRegisters) = context.Cpsr;
403
404     assert(sizeof(m_fpRegisters.vregs) == sizeof(context.V));
405     memcpy(m_fpRegisters.vregs, context.V, sizeof(context.V));
406     m_fpRegisters.fpcr = context.Fpcr;
407     m_fpRegisters.fpsr = context.Fpsr;
408 #elif defined(__arm__)
409     m_gpRegisters.ARM_sp = context.Sp;
410     m_gpRegisters.ARM_lr = context.Lr;
411     m_gpRegisters.ARM_pc = context.Pc;
412     m_gpRegisters.ARM_cpsr = context.Cpsr;
413
414     m_gpRegisters.ARM_r0 = context.R0;
415     m_gpRegisters.ARM_ORIG_r0 = context.R0;
416     m_gpRegisters.ARM_r1 = context.R1;
417     m_gpRegisters.ARM_r2 = context.R2;
418     m_gpRegisters.ARM_r3 = context.R3;
419     m_gpRegisters.ARM_r4 = context.R4;
420     m_gpRegisters.ARM_r5 = context.R5;
421     m_gpRegisters.ARM_r6 = context.R6;
422     m_gpRegisters.ARM_r7 = context.R7;
423     m_gpRegisters.ARM_r8 = context.R8;
424     m_gpRegisters.ARM_r9 = context.R9;
425     m_gpRegisters.ARM_r10 = context.R10;
426     m_gpRegisters.ARM_fp = context.R11;
427     m_gpRegisters.ARM_ip = context.R12;
428
429 #if defined(__VFP_FP__) && !defined(__SOFTFP__)
430     m_vfpRegisters.fpscr = context.Fpscr;
431
432     assert(sizeof(context.D) == sizeof(m_vfpRegisters.fpregs));
433     memcpy(m_vfpRegisters.fpregs, context.D, sizeof(context.D));
434 #endif
435 #elif defined(__i386__)
436     m_gpRegisters.ebp = context.Ebp;
437     m_gpRegisters.eip = context.Eip;
438     m_gpRegisters.eflags = context.EFlags;
439     m_gpRegisters.esp = context.Esp;
440     m_gpRegisters.edi = context.Edi;
441
442     m_gpRegisters.esi = context.Esi;
443     m_gpRegisters.ebx = context.Ebx;
444     m_gpRegisters.edx = context.Edx;
445     m_gpRegisters.ecx = context.Ecx;
446     m_gpRegisters.eax = context.Eax;
447     m_gpRegisters.orig_eax = context.Eax;
448 #else
449 #error Platform not supported
450 #endif
451     return true;
452 }
453
454 void
455 ThreadInfo::GetThreadStack(CrashInfo& crashInfo)
456 {
457     uint64_t startAddress;
458     size_t size;
459
460 #if defined(__aarch64__)
461     startAddress = MCREG_Sp(m_gpRegisters) & PAGE_MASK;
462 #elif defined(__arm__)
463     startAddress = m_gpRegisters.ARM_sp & PAGE_MASK;
464 #elif defined(__x86_64__)
465     startAddress = m_gpRegisters.rsp & PAGE_MASK;
466 #elif defined(__i386__)
467     startAddress = m_gpRegisters.esp & PAGE_MASK;
468 #endif
469     size = 4 * PAGE_SIZE;
470
471     MemoryRegion search(0, startAddress, startAddress + PAGE_SIZE);
472     const MemoryRegion* region = CrashInfo::SearchMemoryRegions(crashInfo.OtherMappings(), search);
473     if (region != nullptr) {
474
475         // Use the mapping found for the size of the thread's stack
476         size = region->EndAddress() - startAddress;
477
478         if (g_diagnostics)
479         {
480             TRACE("Thread %04x stack found in other mapping (size %08zx): ", m_tid, size);
481             region->Trace();
482         }
483     }
484     crashInfo.InsertMemoryRegion(startAddress, size);
485 }
486
487 void 
488 ThreadInfo::GetThreadContext(uint32_t flags, CONTEXT* context) const
489 {
490     context->ContextFlags = flags;
491 #if defined(__x86_64__)
492     if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
493     {
494         context->Rbp = m_gpRegisters.rbp;
495         context->Rip = m_gpRegisters.rip;
496         context->SegCs = m_gpRegisters.cs;
497         context->EFlags = m_gpRegisters.eflags;
498         context->SegSs = m_gpRegisters.ss;
499         context->Rsp = m_gpRegisters.rsp;
500     }
501     if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
502     {
503         context->Rdi = m_gpRegisters.rdi;
504         context->Rsi = m_gpRegisters.rsi;
505         context->Rbx = m_gpRegisters.rbx;
506         context->Rdx = m_gpRegisters.rdx;
507         context->Rcx = m_gpRegisters.rcx;
508         context->Rax = m_gpRegisters.rax;
509         context->R8 = m_gpRegisters.r8;
510         context->R9 = m_gpRegisters.r9;
511         context->R10 = m_gpRegisters.r10;
512         context->R11 = m_gpRegisters.r11;
513         context->R12 = m_gpRegisters.r12;
514         context->R13 = m_gpRegisters.r13;
515         context->R14 = m_gpRegisters.r14;
516         context->R15 = m_gpRegisters.r15;
517     }
518     if ((flags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
519     {
520         context->SegDs = m_gpRegisters.ds;
521         context->SegEs = m_gpRegisters.es;
522         context->SegFs = m_gpRegisters.fs;
523         context->SegGs = m_gpRegisters.gs;
524     }
525     if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
526     {
527         context->FltSave.ControlWord = m_fpRegisters.cwd;
528         context->FltSave.StatusWord = m_fpRegisters.swd;
529         context->FltSave.TagWord = m_fpRegisters.ftw;
530         context->FltSave.ErrorOpcode = m_fpRegisters.fop;
531
532         context->FltSave.ErrorOffset = FPREG_ErrorOffset(m_fpRegisters);
533         context->FltSave.ErrorSelector = FPREG_ErrorSelector(m_fpRegisters);
534         context->FltSave.DataOffset = FPREG_DataOffset(m_fpRegisters);
535         context->FltSave.DataSelector = FPREG_DataSelector(m_fpRegisters);
536
537         context->FltSave.MxCsr = m_fpRegisters.mxcsr;
538         context->FltSave.MxCsr_Mask = m_fpRegisters.mxcr_mask;
539
540         assert(sizeof(context->FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space));
541         memcpy(context->FltSave.FloatRegisters, m_fpRegisters.st_space, sizeof(context->FltSave.FloatRegisters));
542
543         assert(sizeof(context->FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space));
544         memcpy(context->FltSave.XmmRegisters, m_fpRegisters.xmm_space, sizeof(context->FltSave.XmmRegisters));
545     }
546     // TODO: debug registers?
547 #elif defined(__aarch64__)
548     if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
549     {
550         context->Fp = MCREG_Fp(m_gpRegisters);
551         context->Lr = MCREG_Lr(m_gpRegisters);
552         context->Sp = MCREG_Sp(m_gpRegisters);
553         context->Pc = MCREG_Pc(m_gpRegisters);
554         context->Cpsr = MCREG_Cpsr(m_gpRegisters);
555     }
556     if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
557     {
558         assert(sizeof(m_gpRegisters.regs) == (sizeof(context->X) + sizeof(context->Fp) + sizeof(context->Lr)));
559         memcpy(context->X, m_gpRegisters.regs, sizeof(context->X));
560     }
561     if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
562     {
563         assert(sizeof(m_fpRegisters.vregs) == sizeof(context->V));
564         memcpy(context->V, m_fpRegisters.vregs, sizeof(context->V));
565         context->Fpcr = m_fpRegisters.fpcr;
566         context->Fpsr = m_fpRegisters.fpsr;
567     }
568 #elif defined(__arm__)
569     if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
570     {
571         context->Sp = m_gpRegisters.ARM_sp;
572         context->Lr = m_gpRegisters.ARM_lr;
573         context->Pc = m_gpRegisters.ARM_pc;
574         context->Cpsr = m_gpRegisters.ARM_cpsr;
575     }
576     if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
577     {
578         context->R0 = m_gpRegisters.ARM_r0;
579         context->R1 = m_gpRegisters.ARM_r1;
580         context->R2 = m_gpRegisters.ARM_r2;
581         context->R3 = m_gpRegisters.ARM_r3;
582         context->R4 = m_gpRegisters.ARM_r4;
583         context->R5 = m_gpRegisters.ARM_r5;
584         context->R6 = m_gpRegisters.ARM_r6;
585         context->R7 = m_gpRegisters.ARM_r7;
586         context->R8 = m_gpRegisters.ARM_r8;
587         context->R9 = m_gpRegisters.ARM_r9;
588         context->R10 = m_gpRegisters.ARM_r10;
589         context->R11 = m_gpRegisters.ARM_fp;
590         context->R12 = m_gpRegisters.ARM_ip;
591     }
592     if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
593     {
594 #if defined(__VFP_FP__) && !defined(__SOFTFP__)
595         context->Fpscr = m_vfpRegisters.fpscr;
596
597         assert(sizeof(context->D) == sizeof(m_vfpRegisters.fpregs));
598         memcpy(context->D, m_vfpRegisters.fpregs, sizeof(context->D));
599 #endif
600     }
601 #elif defined(__i386__)
602     if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
603     {
604         context->Ebp = m_gpRegisters.ebp;
605         context->Eip = m_gpRegisters.eip;
606         context->EFlags = m_gpRegisters.eflags;
607         context->Esp = m_gpRegisters.esp;
608         context->SegCs = m_gpRegisters.xcs;
609         context->SegSs = m_gpRegisters.xss;
610         context->SegGs_PAL_Undefined = m_gpRegisters.xgs;
611         context->SegFs_PAL_Undefined = m_gpRegisters.xfs;
612         context->SegEs_PAL_Undefined = m_gpRegisters.xes;
613         context->SegDs_PAL_Undefined = m_gpRegisters.xds;
614     }
615     if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
616     {
617         context->Edi = m_gpRegisters.edi;
618         context->Esi = m_gpRegisters.esi;
619         context->Ebx = m_gpRegisters.ebx;
620         context->Edx = m_gpRegisters.edx;
621         context->Ecx = m_gpRegisters.ecx;
622         context->Eax = m_gpRegisters.eax;
623     }
624 #else
625 #error Platform not supported
626 #endif
627 }