02233c14dd7e30cfab88cc070b7bc451fd3b462a
[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 #else
69 #error "Unsupported architecture"
70 #endif
71     return true;
72 }
73
74 void
75 ThreadInfo::ResumeThread()
76 {
77     if (ptrace(PTRACE_DETACH, m_tid, nullptr, nullptr) != -1)
78     {
79         int waitStatus;
80         waitpid(m_tid, &waitStatus, __WALL);
81     }
82 }
83
84 // Helper for UnwindNativeFrames
85 static void
86 GetFrameLocation(CONTEXT* pContext, uint64_t* ip, uint64_t* sp)
87 {
88 #if defined(__x86_64__)
89     *ip = pContext->Rip;
90     *sp = pContext->Rsp;
91 #elif defined(__i386__)
92     *ip = pContext->Eip;
93     *sp = pContext->Esp;
94 #elif defined(__aarch64__)
95     *ip = pContext->Pc;
96     *sp = pContext->Sp;
97 #elif defined(__arm__)
98     *ip = pContext->Pc & ~THUMB_CODE;
99     *sp = pContext->Sp;
100 #endif
101 }
102
103 // Helper for UnwindNativeFrames
104 static BOOL 
105 ReadMemoryAdapter(PVOID address, PVOID buffer, SIZE_T size)
106 {
107     return g_crashInfo->ReadMemory(address, buffer, size);
108 }
109
110 void
111 ThreadInfo::UnwindNativeFrames(CrashInfo& crashInfo, CONTEXT* pContext)
112 {
113     uint64_t previousSp = 0;
114
115     // For each native frame
116     while (true)
117     {
118         uint64_t ip = 0, sp = 0;
119         GetFrameLocation(pContext, &ip, &sp);
120
121         TRACE("Unwind: sp %" PRIA PRIx64 " ip %" PRIA PRIx64 "\n", sp, ip);
122         if (ip == 0 || sp <= previousSp) {
123             break;
124         }
125
126         // Add two pages around the instruction pointer to the core dump
127         crashInfo.InsertMemoryRegion(ip - PAGE_SIZE, PAGE_SIZE * 2);
128
129         // Look up the ip address to get the module base address
130         uint64_t baseAddress = crashInfo.GetBaseAddress(ip);
131         if (baseAddress == 0) {
132             TRACE("Unwind: module base not found ip %" PRIA PRIx64 "\n", ip);
133             break;
134         }
135
136         // Unwind the native frame adding all the memory accessed to the 
137         // core dump via the read memory adapter.
138         if (!PAL_VirtualUnwindOutOfProc(pContext, nullptr, baseAddress, ReadMemoryAdapter)) {
139             TRACE("Unwind: PAL_VirtualUnwindOutOfProc returned false\n");
140             break;
141         }
142         previousSp = sp;
143     }
144 }
145
146 bool
147 ThreadInfo::UnwindThread(CrashInfo& crashInfo, IXCLRDataProcess* pClrDataProcess)
148 {
149     TRACE("Unwind: thread %04x\n", Tid());
150
151     // Get starting native context for the thread
152     CONTEXT context;
153     GetThreadContext(CONTEXT_ALL, &context);
154
155     // Unwind the native frames at the top of the stack
156     UnwindNativeFrames(crashInfo, &context);
157
158     if (pClrDataProcess != nullptr)
159     {
160         ReleaseHolder<IXCLRDataTask> pTask;
161         ReleaseHolder<IXCLRDataStackWalk> pStackwalk;
162
163         // Get the managed stack walker for this thread
164         if (SUCCEEDED(pClrDataProcess->GetTaskByOSThreadID(Tid(), &pTask)))
165         {
166             pTask->CreateStackWalk(
167                 CLRDATA_SIMPFRAME_UNRECOGNIZED |
168                 CLRDATA_SIMPFRAME_MANAGED_METHOD |
169                 CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE |
170                 CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE,
171                 &pStackwalk);
172         }
173
174         // For each managed frame (if any)
175         if (pStackwalk != nullptr)
176         {
177             TRACE("Unwind: managed frames\n");
178             do
179             {
180                 // Get the managed stack frame context
181                 if (pStackwalk->GetContext(CONTEXT_ALL, sizeof(context), nullptr, (BYTE *)&context) != S_OK) {
182                     TRACE("Unwind: stack walker GetContext FAILED\n");
183                     break;
184                 }
185
186                 // Unwind all the native frames after the managed frame
187                 UnwindNativeFrames(crashInfo, &context);
188
189             } while (pStackwalk->Next() == S_OK);
190         }
191     }
192
193     return true;
194 }
195
196 bool 
197 ThreadInfo::GetRegistersWithPTrace()
198 {
199 #if defined(__aarch64__)
200     struct iovec gpRegsVec = { &m_gpRegisters, sizeof(m_gpRegisters) };
201     if (ptrace((__ptrace_request)PTRACE_GETREGSET, m_tid, NT_PRSTATUS, &gpRegsVec) == -1)
202     {
203         fprintf(stderr, "ptrace(PTRACE_GETREGSET, %d, NT_PRSTATUS) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
204         return false;
205     }
206     assert(sizeof(m_gpRegisters) == gpRegsVec.iov_len);
207
208     struct iovec fpRegsVec = { &m_fpRegisters, sizeof(m_fpRegisters) };
209     if (ptrace((__ptrace_request)PTRACE_GETREGSET, m_tid, NT_FPREGSET, &fpRegsVec) == -1)
210     {
211         fprintf(stderr, "ptrace(PTRACE_GETREGSET, %d, NT_FPREGSET) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
212         return false;
213     }
214     assert(sizeof(m_fpRegisters) == fpRegsVec.iov_len);
215 #else
216     if (ptrace((__ptrace_request)PTRACE_GETREGS, m_tid, nullptr, &m_gpRegisters) == -1)
217     {
218         fprintf(stderr, "ptrace(GETREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
219         return false;
220     }
221     if (ptrace((__ptrace_request)PTRACE_GETFPREGS, m_tid, nullptr, &m_fpRegisters) == -1)
222     {
223         fprintf(stderr, "ptrace(GETFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
224         return false;
225     }
226 #if defined(__i386__)
227     if (ptrace((__ptrace_request)PTRACE_GETFPXREGS, m_tid, nullptr, &m_fpxRegisters) == -1)
228     {
229         fprintf(stderr, "ptrace(GETFPXREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
230         return false;
231     }
232 #elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__)
233
234 #if defined(ARM_VFPREGS_SIZE)
235     assert(sizeof(m_vfpRegisters) == ARM_VFPREGS_SIZE);
236 #endif
237
238     if (ptrace((__ptrace_request)PTRACE_GETVFPREGS, m_tid, nullptr, &m_vfpRegisters) == -1)
239     {
240         fprintf(stderr, "ptrace(PTRACE_GETVFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
241         return false;
242     }
243 #endif
244 #endif
245     return true;
246 }
247
248 bool 
249 ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* pDataTarget)
250 {
251     CONTEXT context;
252     context.ContextFlags = CONTEXT_ALL;
253     if (pDataTarget->GetThreadContext(m_tid, context.ContextFlags, sizeof(context), reinterpret_cast<PBYTE>(&context)) != S_OK)
254     {
255         return false;
256     }
257 #if defined(__x86_64__)
258     m_gpRegisters.rbp = context.Rbp;
259     m_gpRegisters.rip = context.Rip;
260     m_gpRegisters.cs = context.SegCs;
261     m_gpRegisters.eflags = context.EFlags;
262     m_gpRegisters.ss = context.SegSs;
263     m_gpRegisters.rsp = context.Rsp;
264     m_gpRegisters.rdi = context.Rdi;
265
266     m_gpRegisters.rsi = context.Rsi;
267     m_gpRegisters.rbx = context.Rbx;
268     m_gpRegisters.rdx = context.Rdx;
269     m_gpRegisters.rcx = context.Rcx;
270     m_gpRegisters.rax = context.Rax;
271     m_gpRegisters.orig_rax = context.Rax;
272     m_gpRegisters.r8 = context.R8;
273     m_gpRegisters.r9 = context.R9;
274     m_gpRegisters.r10 = context.R10;
275     m_gpRegisters.r11 = context.R11;
276     m_gpRegisters.r12 = context.R12;
277     m_gpRegisters.r13 = context.R13;
278     m_gpRegisters.r14 = context.R14;
279     m_gpRegisters.r15 = context.R15;
280
281     m_gpRegisters.ds = context.SegDs;
282     m_gpRegisters.es = context.SegEs;
283     m_gpRegisters.fs = context.SegFs;
284     m_gpRegisters.gs = context.SegGs;
285     m_gpRegisters.fs_base = 0;
286     m_gpRegisters.gs_base = 0;
287
288     m_fpRegisters.cwd = context.FltSave.ControlWord;
289     m_fpRegisters.swd = context.FltSave.StatusWord;
290     m_fpRegisters.ftw = context.FltSave.TagWord;
291     m_fpRegisters.fop = context.FltSave.ErrorOpcode;
292
293     FPREG_ErrorOffset(m_fpRegisters) = context.FltSave.ErrorOffset;
294     FPREG_ErrorSelector(m_fpRegisters) = context.FltSave.ErrorSelector;
295     FPREG_DataOffset(m_fpRegisters) = context.FltSave.DataOffset;
296     FPREG_DataSelector(m_fpRegisters) = context.FltSave.DataSelector;
297
298     m_fpRegisters.mxcsr = context.FltSave.MxCsr;
299     m_fpRegisters.mxcr_mask = context.FltSave.MxCsr_Mask;
300
301     assert(sizeof(context.FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space));
302     memcpy(m_fpRegisters.st_space, context.FltSave.FloatRegisters, sizeof(m_fpRegisters.st_space));
303
304     assert(sizeof(context.FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space));
305     memcpy(m_fpRegisters.xmm_space, context.FltSave.XmmRegisters, sizeof(m_fpRegisters.xmm_space));
306 #elif defined(__aarch64__)
307     // See MCREG maps in PAL's context.h
308     assert(sizeof(m_gpRegisters.regs) == (sizeof(context.X) + sizeof(context.Fp) + sizeof(context.Lr)));
309     memcpy(m_gpRegisters.regs, context.X, sizeof(context.X));
310     MCREG_Fp(m_gpRegisters) = context.Fp;
311     MCREG_Lr(m_gpRegisters) = context.Lr;
312     MCREG_Sp(m_gpRegisters) = context.Sp;
313     MCREG_Pc(m_gpRegisters) = context.Pc;
314     MCREG_Cpsr(m_gpRegisters) = context.Cpsr;
315
316     assert(sizeof(m_fpRegisters.vregs) == sizeof(context.V));
317     memcpy(m_fpRegisters.vregs, context.V, sizeof(context.V));
318     m_fpRegisters.fpcr = context.Fpcr;
319     m_fpRegisters.fpsr = context.Fpsr;
320 #elif defined(__arm__)
321     m_gpRegisters.ARM_sp = context.Sp;
322     m_gpRegisters.ARM_lr = context.Lr;
323     m_gpRegisters.ARM_pc = context.Pc;
324     m_gpRegisters.ARM_cpsr = context.Cpsr;
325
326     m_gpRegisters.ARM_r0 = context.R0;
327     m_gpRegisters.ARM_ORIG_r0 = context.R0;
328     m_gpRegisters.ARM_r1 = context.R1;
329     m_gpRegisters.ARM_r2 = context.R2;
330     m_gpRegisters.ARM_r3 = context.R3;
331     m_gpRegisters.ARM_r4 = context.R4;
332     m_gpRegisters.ARM_r5 = context.R5;
333     m_gpRegisters.ARM_r6 = context.R6;
334     m_gpRegisters.ARM_r7 = context.R7;
335     m_gpRegisters.ARM_r8 = context.R8;
336     m_gpRegisters.ARM_r9 = context.R9;
337     m_gpRegisters.ARM_r10 = context.R10;
338     m_gpRegisters.ARM_fp = context.R11;
339     m_gpRegisters.ARM_ip = context.R12;
340
341 #if defined(__VFP_FP__) && !defined(__SOFTFP__)
342     m_vfpRegisters.fpscr = context.Fpscr;
343
344     assert(sizeof(context.D) == sizeof(m_vfpRegisters.fpregs));
345     memcpy(m_vfpRegisters.fpregs, context.D, sizeof(context.D));
346 #endif
347 #else 
348 #error Platform not supported
349 #endif
350     return true;
351 }
352
353 void
354 ThreadInfo::GetThreadStack(CrashInfo& crashInfo)
355 {
356     uint64_t startAddress;
357     size_t size;
358
359 #if defined(__aarch64__)
360     startAddress = MCREG_Sp(m_gpRegisters) & PAGE_MASK;
361 #elif defined(__arm__)
362     startAddress = m_gpRegisters.ARM_sp & PAGE_MASK;
363 #else
364     startAddress = m_gpRegisters.rsp & PAGE_MASK;
365 #endif
366     size = 4 * PAGE_SIZE;
367
368     MemoryRegion search(0, startAddress, startAddress + PAGE_SIZE);
369     const MemoryRegion* region = CrashInfo::SearchMemoryRegions(crashInfo.OtherMappings(), search);
370     if (region != nullptr) {
371
372         // Use the mapping found for the size of the thread's stack
373         size = region->EndAddress() - startAddress;
374
375         if (g_diagnostics)
376         {
377             TRACE("Thread %04x stack found in other mapping (size %08zx): ", m_tid, size);
378             region->Trace();
379         }
380     }
381     crashInfo.InsertMemoryRegion(startAddress, size);
382 }
383
384 void 
385 ThreadInfo::GetThreadContext(uint32_t flags, CONTEXT* context) const
386 {
387     context->ContextFlags = flags;
388 #if defined(__x86_64__)
389     if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
390     {
391         context->Rbp = m_gpRegisters.rbp;
392         context->Rip = m_gpRegisters.rip;
393         context->SegCs = m_gpRegisters.cs;
394         context->EFlags = m_gpRegisters.eflags;
395         context->SegSs = m_gpRegisters.ss;
396         context->Rsp = m_gpRegisters.rsp;
397     }
398     if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
399     {
400         context->Rdi = m_gpRegisters.rdi;
401         context->Rsi = m_gpRegisters.rsi;
402         context->Rbx = m_gpRegisters.rbx;
403         context->Rdx = m_gpRegisters.rdx;
404         context->Rcx = m_gpRegisters.rcx;
405         context->Rax = m_gpRegisters.rax;
406         context->R8 = m_gpRegisters.r8;
407         context->R9 = m_gpRegisters.r9;
408         context->R10 = m_gpRegisters.r10;
409         context->R11 = m_gpRegisters.r11;
410         context->R12 = m_gpRegisters.r12;
411         context->R13 = m_gpRegisters.r13;
412         context->R14 = m_gpRegisters.r14;
413         context->R15 = m_gpRegisters.r15;
414     }
415     if ((flags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
416     {
417         context->SegDs = m_gpRegisters.ds;
418         context->SegEs = m_gpRegisters.es;
419         context->SegFs = m_gpRegisters.fs;
420         context->SegGs = m_gpRegisters.gs;
421     }
422     if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
423     {
424         context->FltSave.ControlWord = m_fpRegisters.cwd;
425         context->FltSave.StatusWord = m_fpRegisters.swd;
426         context->FltSave.TagWord = m_fpRegisters.ftw;
427         context->FltSave.ErrorOpcode = m_fpRegisters.fop;
428
429         context->FltSave.ErrorOffset = FPREG_ErrorOffset(m_fpRegisters);
430         context->FltSave.ErrorSelector = FPREG_ErrorSelector(m_fpRegisters);
431         context->FltSave.DataOffset = FPREG_DataOffset(m_fpRegisters);
432         context->FltSave.DataSelector = FPREG_DataSelector(m_fpRegisters);
433
434         context->FltSave.MxCsr = m_fpRegisters.mxcsr;
435         context->FltSave.MxCsr_Mask = m_fpRegisters.mxcr_mask;
436
437         assert(sizeof(context->FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space));
438         memcpy(context->FltSave.FloatRegisters, m_fpRegisters.st_space, sizeof(context->FltSave.FloatRegisters));
439
440         assert(sizeof(context->FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space));
441         memcpy(context->FltSave.XmmRegisters, m_fpRegisters.xmm_space, sizeof(context->FltSave.XmmRegisters));
442     }
443     // TODO: debug registers?
444 #elif defined(__aarch64__)
445     if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
446     {
447         context->Fp = MCREG_Fp(m_gpRegisters);
448         context->Lr = MCREG_Lr(m_gpRegisters);
449         context->Sp = MCREG_Sp(m_gpRegisters);
450         context->Pc = MCREG_Pc(m_gpRegisters);
451         context->Cpsr = MCREG_Cpsr(m_gpRegisters);
452     }
453     if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
454     {
455         assert(sizeof(m_gpRegisters.regs) == (sizeof(context->X) + sizeof(context->Fp) + sizeof(context->Lr)));
456         memcpy(context->X, m_gpRegisters.regs, sizeof(context->X));
457     }
458     if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
459     {
460         assert(sizeof(m_fpRegisters.vregs) == sizeof(context->V));
461         memcpy(context->V, m_fpRegisters.vregs, sizeof(context->V));
462         context->Fpcr = m_fpRegisters.fpcr;
463         context->Fpsr = m_fpRegisters.fpsr;
464     }
465 #elif defined(__arm__)
466     if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
467     {
468         context->Sp = m_gpRegisters.ARM_sp;
469         context->Lr = m_gpRegisters.ARM_lr;
470         context->Pc = m_gpRegisters.ARM_pc;
471         context->Cpsr = m_gpRegisters.ARM_cpsr;
472     }
473     if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
474     {
475         context->R0 = m_gpRegisters.ARM_r0;
476         context->R1 = m_gpRegisters.ARM_r1;
477         context->R2 = m_gpRegisters.ARM_r2;
478         context->R3 = m_gpRegisters.ARM_r3;
479         context->R4 = m_gpRegisters.ARM_r4;
480         context->R5 = m_gpRegisters.ARM_r5;
481         context->R6 = m_gpRegisters.ARM_r6;
482         context->R7 = m_gpRegisters.ARM_r7;
483         context->R8 = m_gpRegisters.ARM_r8;
484         context->R9 = m_gpRegisters.ARM_r9;
485         context->R10 = m_gpRegisters.ARM_r10;
486         context->R11 = m_gpRegisters.ARM_fp;
487         context->R12 = m_gpRegisters.ARM_ip;
488     }
489     if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
490     {
491 #if defined(__VFP_FP__) && !defined(__SOFTFP__)
492         context->Fpscr = m_vfpRegisters.fpscr;
493
494         assert(sizeof(context->D) == sizeof(m_vfpRegisters.fpregs));
495         memcpy(context->D, m_vfpRegisters.fpregs, sizeof(context->D));
496 #endif
497     }
498 #else
499 #error Platform not supported
500 #endif
501 }