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#ifndef THUMB_CODE
9#define THUMB_CODE 1
10#endif
11
12#ifndef __GLIBC__
13typedef int __ptrace_request;
14#endif
15
16#define FPREG_ErrorOffset(fpregs) *(DWORD*)&((fpregs).rip)
17#define FPREG_ErrorSelector(fpregs) *(((WORD*)&((fpregs).rip)) + 2)
18#define FPREG_DataOffset(fpregs) *(DWORD*)&((fpregs).rdp)
19#define FPREG_DataSelector(fpregs) *(((WORD*)&((fpregs).rdp)) + 2)
20
21extern CrashInfo* g_crashInfo;
22
23ThreadInfo::ThreadInfo(pid_t tid) :
24 m_tid(tid)
25{
26}
27
28ThreadInfo::~ThreadInfo()
29{
30}
31
32bool
33ThreadInfo::Initialize(ICLRDataTarget* pDataTarget)
34{
35 if (!CrashInfo::GetStatus(m_tid, &m_ppid, &m_tgid, nullptr))
36 {
37 return false;
38 }
39 if (pDataTarget != nullptr)
40 {
41 if (!GetRegistersWithDataTarget(pDataTarget))
42 {
43 return false;
44 }
45 }
46 else {
47 if (!GetRegistersWithPTrace())
48 {
49 return false;
50 }
51 }
52
53#if defined(__arm__)
54 TRACE("Thread %04x PC %08lx SP %08lx\n", m_tid, (unsigned long)m_gpRegisters.ARM_pc, (unsigned long)m_gpRegisters.ARM_sp);
55#else
56 TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, (unsigned long long)m_gpRegisters.rip, (unsigned long long)m_gpRegisters.rsp);
57#endif
58 return true;
59}
60
61void
62ThreadInfo::ResumeThread()
63{
64 if (ptrace(PTRACE_DETACH, m_tid, nullptr, nullptr) != -1)
65 {
66 int waitStatus;
67 waitpid(m_tid, &waitStatus, __WALL);
68 }
69}
70
71// Helper for UnwindNativeFrames
72static void
73GetFrameLocation(CONTEXT* pContext, uint64_t* ip, uint64_t* sp)
74{
75#if defined(__x86_64__)
76 *ip = pContext->Rip;
77 *sp = pContext->Rsp;
78#elif defined(__i386__)
79 *ip = pContext->Eip;
80 *sp = pContext->Esp;
81#elif defined(__arm__)
82 *ip = pContext->Pc & ~THUMB_CODE;
83 *sp = pContext->Sp;
84#endif
85}
86
87// Helper for UnwindNativeFrames
88static BOOL
89ReadMemoryAdapter(PVOID address, PVOID buffer, SIZE_T size)
90{
91 return g_crashInfo->ReadMemory(address, buffer, size);
92}
93
94void
95ThreadInfo::UnwindNativeFrames(CrashInfo& crashInfo, CONTEXT* pContext)
96{
97 // For each native frame
98 while (true)
99 {
100 uint64_t ip = 0, sp = 0;
101 GetFrameLocation(pContext, &ip, &sp);
102
103 TRACE("Unwind: sp %" PRIA PRIx64 " ip %" PRIA PRIx64 "\n", sp, ip);
104 if (ip == 0) {
105 break;
106 }
107 // Add two pages around the instruction pointer to the core dump
108 crashInfo.InsertMemoryRegion(ip - PAGE_SIZE, PAGE_SIZE * 2);
109
110 // Look up the ip address to get the module base address
111 uint64_t baseAddress = crashInfo.GetBaseAddress(ip);
112 if (baseAddress == 0) {
113 TRACE("Unwind: module base not found ip %" PRIA PRIx64 "\n", ip);
114 break;
115 }
116
117 // Unwind the native frame adding all the memory accessed to the
118 // core dump via the read memory adapter.
119 if (!PAL_VirtualUnwindOutOfProc(pContext, nullptr, baseAddress, ReadMemoryAdapter)) {
120 TRACE("Unwind: PAL_VirtualUnwindOutOfProc returned false\n");
121 break;
122 }
123 }
124}
125
126bool
127ThreadInfo::UnwindThread(CrashInfo& crashInfo, IXCLRDataProcess* pClrDataProcess)
128{
129 TRACE("Unwind: thread %04x\n", Tid());
130
131 // Get starting native context for the thread
132 CONTEXT context;
133 GetThreadContext(CONTEXT_ALL, &context);
134
135 // Unwind the native frames at the top of the stack
136 UnwindNativeFrames(crashInfo, &context);
137
138 if (pClrDataProcess != nullptr)
139 {
140 ReleaseHolder<IXCLRDataTask> pTask;
141 ReleaseHolder<IXCLRDataStackWalk> pStackwalk;
142
143 // Get the managed stack walker for this thread
144 if (SUCCEEDED(pClrDataProcess->GetTaskByOSThreadID(Tid(), &pTask)))
145 {
146 pTask->CreateStackWalk(
147 CLRDATA_SIMPFRAME_UNRECOGNIZED |
148 CLRDATA_SIMPFRAME_MANAGED_METHOD |
149 CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE |
150 CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE,
151 &pStackwalk);
152 }
153
154 // For each managed frame (if any)
155 if (pStackwalk != nullptr)
156 {
157 TRACE("Unwind: managed frames\n");
158 do
159 {
160 // Get the managed stack frame context
161 if (pStackwalk->GetContext(CONTEXT_ALL, sizeof(context), nullptr, (BYTE *)&context) != S_OK) {
162 TRACE("Unwind: stack walker GetContext FAILED\n");
163 break;
164 }
165
166 // Unwind all the native frames after the managed frame
167 UnwindNativeFrames(crashInfo, &context);
168
169 } while (pStackwalk->Next() == S_OK);
170 }
171 }
172
173 return true;
174}
175
176bool
177ThreadInfo::GetRegistersWithPTrace()
178{
179 if (ptrace((__ptrace_request)PTRACE_GETREGS, m_tid, nullptr, &m_gpRegisters) == -1)
180 {
181 fprintf(stderr, "ptrace(GETREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
182 return false;
183 }
184 if (ptrace((__ptrace_request)PTRACE_GETFPREGS, m_tid, nullptr, &m_fpRegisters) == -1)
185 {
186 fprintf(stderr, "ptrace(GETFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
187 return false;
188 }
189#if defined(__i386__)
190 if (ptrace((__ptrace_request)PTRACE_GETFPXREGS, m_tid, nullptr, &m_fpxRegisters) == -1)
191 {
192 fprintf(stderr, "ptrace(GETFPXREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
193 return false;
194 }
195#elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__)
196
197#if defined(ARM_VFPREGS_SIZE)
198 assert(sizeof(m_vfpRegisters) == ARM_VFPREGS_SIZE);
199#endif
200
201 if (ptrace((__ptrace_request)PTRACE_GETVFPREGS, m_tid, nullptr, &m_vfpRegisters) == -1)
202 {
203 fprintf(stderr, "ptrace(PTRACE_GETVFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno));
204 return false;
205 }
206#endif
207 return true;
208}
209
210bool
211ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* pDataTarget)
212{
213 CONTEXT context;
214 context.ContextFlags = CONTEXT_ALL;
215 if (pDataTarget->GetThreadContext(m_tid, context.ContextFlags, sizeof(context), reinterpret_cast<PBYTE>(&context)) != S_OK)
216 {
217 return false;
218 }
219#if defined(__x86_64__)
220 m_gpRegisters.rbp = context.Rbp;
221 m_gpRegisters.rip = context.Rip;
222 m_gpRegisters.cs = context.SegCs;
223 m_gpRegisters.eflags = context.EFlags;
224 m_gpRegisters.ss = context.SegSs;
225 m_gpRegisters.rsp = context.Rsp;
226 m_gpRegisters.rdi = context.Rdi;
227
228 m_gpRegisters.rsi = context.Rsi;
229 m_gpRegisters.rbx = context.Rbx;
230 m_gpRegisters.rdx = context.Rdx;
231 m_gpRegisters.rcx = context.Rcx;
232 m_gpRegisters.rax = context.Rax;
233 m_gpRegisters.orig_rax = context.Rax;
234 m_gpRegisters.r8 = context.R8;
235 m_gpRegisters.r9 = context.R9;
236 m_gpRegisters.r10 = context.R10;
237 m_gpRegisters.r11 = context.R11;
238 m_gpRegisters.r12 = context.R12;
239 m_gpRegisters.r13 = context.R13;
240 m_gpRegisters.r14 = context.R14;
241 m_gpRegisters.r15 = context.R15;
242
243 m_gpRegisters.ds = context.SegDs;
244 m_gpRegisters.es = context.SegEs;
245 m_gpRegisters.fs = context.SegFs;
246 m_gpRegisters.gs = context.SegGs;
247 m_gpRegisters.fs_base = 0;
248 m_gpRegisters.gs_base = 0;
249
250 m_fpRegisters.cwd = context.FltSave.ControlWord;
251 m_fpRegisters.swd = context.FltSave.StatusWord;
252 m_fpRegisters.ftw = context.FltSave.TagWord;
253 m_fpRegisters.fop = context.FltSave.ErrorOpcode;
254
255 FPREG_ErrorOffset(m_fpRegisters) = context.FltSave.ErrorOffset;
256 FPREG_ErrorSelector(m_fpRegisters) = context.FltSave.ErrorSelector;
257 FPREG_DataOffset(m_fpRegisters) = context.FltSave.DataOffset;
258 FPREG_DataSelector(m_fpRegisters) = context.FltSave.DataSelector;
259
260 m_fpRegisters.mxcsr = context.FltSave.MxCsr;
261 m_fpRegisters.mxcr_mask = context.FltSave.MxCsr_Mask;
262
263 assert(sizeof(context.FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space));
264 memcpy(m_fpRegisters.st_space, context.FltSave.FloatRegisters, sizeof(m_fpRegisters.st_space));
265
266 assert(sizeof(context.FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space));
267 memcpy(m_fpRegisters.xmm_space, context.FltSave.XmmRegisters, sizeof(m_fpRegisters.xmm_space));
268#elif defined(__arm__)
269 m_gpRegisters.ARM_sp = context.Sp;
270 m_gpRegisters.ARM_lr = context.Lr;
271 m_gpRegisters.ARM_pc = context.Pc;
272 m_gpRegisters.ARM_cpsr = context.Cpsr;
273
274 m_gpRegisters.ARM_r0 = context.R0;
275 m_gpRegisters.ARM_ORIG_r0 = context.R0;
276 m_gpRegisters.ARM_r1 = context.R1;
277 m_gpRegisters.ARM_r2 = context.R2;
278 m_gpRegisters.ARM_r3 = context.R3;
279 m_gpRegisters.ARM_r4 = context.R4;
280 m_gpRegisters.ARM_r5 = context.R5;
281 m_gpRegisters.ARM_r6 = context.R6;
282 m_gpRegisters.ARM_r7 = context.R7;
283 m_gpRegisters.ARM_r8 = context.R8;
284 m_gpRegisters.ARM_r9 = context.R9;
285 m_gpRegisters.ARM_r10 = context.R10;
286 m_gpRegisters.ARM_fp = context.R11;
287 m_gpRegisters.ARM_ip = context.R12;
288
289#if defined(__VFP_FP__) && !defined(__SOFTFP__)
290 m_vfpRegisters.fpscr = context.Fpscr;
291
292 assert(sizeof(context.D) == sizeof(m_vfpRegisters.fpregs));
293 memcpy(m_vfpRegisters.fpregs, context.D, sizeof(context.D));
294#endif
295#else
296#error Platform not supported
297#endif
298 return true;
299}
300
301void
302ThreadInfo::GetThreadStack(CrashInfo& crashInfo)
303{
304 uint64_t startAddress;
305 size_t size;
306
307#if defined(__arm__)
308 startAddress = m_gpRegisters.ARM_sp & PAGE_MASK;
309#else
310 startAddress = m_gpRegisters.rsp & PAGE_MASK;
311#endif
312 size = 4 * PAGE_SIZE;
313
314 MemoryRegion search(0, startAddress, startAddress + PAGE_SIZE);
315 const MemoryRegion* region = CrashInfo::SearchMemoryRegions(crashInfo.OtherMappings(), search);
316 if (region != nullptr) {
317
318 // Use the mapping found for the size of the thread's stack
319 size = region->EndAddress() - startAddress;
320
321 if (g_diagnostics)
322 {
323 TRACE("Thread %04x stack found in other mapping (size %08zx): ", m_tid, size);
324 region->Trace();
325 }
326 }
327 crashInfo.InsertMemoryRegion(startAddress, size);
328}
329
330void
331ThreadInfo::GetThreadContext(uint32_t flags, CONTEXT* context) const
332{
333 context->ContextFlags = flags;
334#if defined(__x86_64__)
335 if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
336 {
337 context->Rbp = m_gpRegisters.rbp;
338 context->Rip = m_gpRegisters.rip;
339 context->SegCs = m_gpRegisters.cs;
340 context->EFlags = m_gpRegisters.eflags;
341 context->SegSs = m_gpRegisters.ss;
342 context->Rsp = m_gpRegisters.rsp;
343 }
344 if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
345 {
346 context->Rdi = m_gpRegisters.rdi;
347 context->Rsi = m_gpRegisters.rsi;
348 context->Rbx = m_gpRegisters.rbx;
349 context->Rdx = m_gpRegisters.rdx;
350 context->Rcx = m_gpRegisters.rcx;
351 context->Rax = m_gpRegisters.rax;
352 context->R8 = m_gpRegisters.r8;
353 context->R9 = m_gpRegisters.r9;
354 context->R10 = m_gpRegisters.r10;
355 context->R11 = m_gpRegisters.r11;
356 context->R12 = m_gpRegisters.r12;
357 context->R13 = m_gpRegisters.r13;
358 context->R14 = m_gpRegisters.r14;
359 context->R15 = m_gpRegisters.r15;
360 }
361 if ((flags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
362 {
363 context->SegDs = m_gpRegisters.ds;
364 context->SegEs = m_gpRegisters.es;
365 context->SegFs = m_gpRegisters.fs;
366 context->SegGs = m_gpRegisters.gs;
367 }
368 if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
369 {
370 context->FltSave.ControlWord = m_fpRegisters.cwd;
371 context->FltSave.StatusWord = m_fpRegisters.swd;
372 context->FltSave.TagWord = m_fpRegisters.ftw;
373 context->FltSave.ErrorOpcode = m_fpRegisters.fop;
374
375 context->FltSave.ErrorOffset = FPREG_ErrorOffset(m_fpRegisters);
376 context->FltSave.ErrorSelector = FPREG_ErrorSelector(m_fpRegisters);
377 context->FltSave.DataOffset = FPREG_DataOffset(m_fpRegisters);
378 context->FltSave.DataSelector = FPREG_DataSelector(m_fpRegisters);
379
380 context->FltSave.MxCsr = m_fpRegisters.mxcsr;
381 context->FltSave.MxCsr_Mask = m_fpRegisters.mxcr_mask;
382
383 assert(sizeof(context->FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space));
384 memcpy(context->FltSave.FloatRegisters, m_fpRegisters.st_space, sizeof(context->FltSave.FloatRegisters));
385
386 assert(sizeof(context->FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space));
387 memcpy(context->FltSave.XmmRegisters, m_fpRegisters.xmm_space, sizeof(context->FltSave.XmmRegisters));
388 }
389 // TODO: debug registers?
390#elif defined(__arm__)
391 if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
392 {
393 context->Sp = m_gpRegisters.ARM_sp;
394 context->Lr = m_gpRegisters.ARM_lr;
395 context->Pc = m_gpRegisters.ARM_pc;
396 context->Cpsr = m_gpRegisters.ARM_cpsr;
397
398 }
399 if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
400 {
401 context->R0 = m_gpRegisters.ARM_r0;
402 context->R1 = m_gpRegisters.ARM_r1;
403 context->R2 = m_gpRegisters.ARM_r2;
404 context->R3 = m_gpRegisters.ARM_r3;
405 context->R4 = m_gpRegisters.ARM_r4;
406 context->R5 = m_gpRegisters.ARM_r5;
407 context->R6 = m_gpRegisters.ARM_r6;
408 context->R7 = m_gpRegisters.ARM_r7;
409 context->R8 = m_gpRegisters.ARM_r8;
410 context->R9 = m_gpRegisters.ARM_r9;
411 context->R10 = m_gpRegisters.ARM_r10;
412 context->R11 = m_gpRegisters.ARM_fp;
413 context->R12 = m_gpRegisters.ARM_ip;
414 }
415 if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
416 {
417#if defined(__VFP_FP__) && !defined(__SOFTFP__)
418 context->Fpscr = m_vfpRegisters.fpscr;
419
420 assert(sizeof(context->D) == sizeof(m_vfpRegisters.fpregs));
421 memcpy(context->D, m_vfpRegisters.fpregs, sizeof(context->D));
422#endif
423 }
424#else
425#error Platform not supported
426#endif
427}
428