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
7#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
8
9DumpDataTarget::DumpDataTarget(pid_t pid) :
10 m_ref(1),
11 m_pid(pid),
12 m_fd(-1),
13 m_crashInfo(nullptr)
14{
15}
16
17DumpDataTarget::~DumpDataTarget()
18{
19 if (m_fd != -1)
20 {
21 close(m_fd);
22 m_fd = -1;
23 }
24}
25
26bool
27DumpDataTarget::Initialize(CrashInfo * crashInfo)
28{
29 char memPath[128];
30 _snprintf_s(memPath, sizeof(memPath), sizeof(memPath), "/proc/%lu/mem", m_pid);
31
32 m_fd = open(memPath, O_RDONLY);
33 if (m_fd == -1)
34 {
35 fprintf(stderr, "open(%s) FAILED %d (%s)\n", memPath, errno, strerror(errno));
36 return false;
37 }
38 m_crashInfo = crashInfo;
39 return true;
40}
41
42STDMETHODIMP
43DumpDataTarget::QueryInterface(
44 ___in REFIID InterfaceId,
45 ___out PVOID* Interface
46 )
47{
48 if (InterfaceId == IID_IUnknown ||
49 InterfaceId == IID_ICLRDataTarget)
50 {
51 *Interface = (ICLRDataTarget*)this;
52 AddRef();
53 return S_OK;
54 }
55 else
56 {
57 *Interface = NULL;
58 return E_NOINTERFACE;
59 }
60}
61
62STDMETHODIMP_(ULONG)
63DumpDataTarget::AddRef()
64{
65 LONG ref = InterlockedIncrement(&m_ref);
66 return ref;
67}
68
69STDMETHODIMP_(ULONG)
70DumpDataTarget::Release()
71{
72 LONG ref = InterlockedDecrement(&m_ref);
73 if (ref == 0)
74 {
75 delete this;
76 }
77 return ref;
78}
79
80HRESULT STDMETHODCALLTYPE
81DumpDataTarget::GetMachineType(
82 /* [out] */ ULONG32 *machine)
83{
84#ifdef _AMD64_
85 *machine = IMAGE_FILE_MACHINE_AMD64;
86#elif _ARM_
87 *machine = IMAGE_FILE_MACHINE_ARMNT;
88#elif _ARM64_
89 *machine = IMAGE_FILE_MACHINE_ARM64;
90#elif _X86_
91 *machine = IMAGE_FILE_MACHINE_I386;
92#else
93#error Unsupported architecture
94#endif
95 return S_OK;
96}
97
98HRESULT STDMETHODCALLTYPE
99DumpDataTarget::GetPointerSize(
100 /* [out] */ ULONG32 *size)
101{
102#if defined(_AMD64_) || defined(_ARM64_)
103 *size = 8;
104#elif defined(_ARM_) || defined(_X86_)
105 *size = 4;
106#else
107#error Unsupported architecture
108#endif
109 return S_OK;
110}
111
112HRESULT STDMETHODCALLTYPE
113DumpDataTarget::GetImageBase(
114 /* [string][in] */ LPCWSTR moduleName,
115 /* [out] */ CLRDATA_ADDRESS *baseAddress)
116{
117 assert(m_crashInfo != nullptr);
118 *baseAddress = 0;
119
120 char tempModuleName[MAX_PATH];
121 int length = WideCharToMultiByte(CP_ACP, 0, moduleName, -1, tempModuleName, sizeof(tempModuleName), NULL, NULL);
122 if (length > 0)
123 {
124 for (const MemoryRegion& image : m_crashInfo->ModuleMappings())
125 {
126 const char *name = strrchr(image.FileName(), '/');
127 if (name != nullptr)
128 {
129 name++;
130 }
131 else
132 {
133 name = image.FileName();
134 }
135 if (strcmp(name, tempModuleName) == 0)
136 {
137 *baseAddress = image.StartAddress();
138 return S_OK;
139 }
140 }
141 }
142 return E_FAIL;
143}
144
145HRESULT STDMETHODCALLTYPE
146DumpDataTarget::ReadVirtual(
147 /* [in] */ CLRDATA_ADDRESS address,
148 /* [length_is][size_is][out] */ PBYTE buffer,
149 /* [in] */ ULONG32 size,
150 /* [optional][out] */ ULONG32 *done)
151{
152 assert(m_fd != -1);
153 size_t read = pread64(m_fd, buffer, size, (off64_t)(ULONG_PTR)address);
154 if (read == -1)
155 {
156 *done = 0;
157 return E_FAIL;
158 }
159 *done = read;
160 return S_OK;
161}
162
163HRESULT STDMETHODCALLTYPE
164DumpDataTarget::WriteVirtual(
165 /* [in] */ CLRDATA_ADDRESS address,
166 /* [size_is][in] */ PBYTE buffer,
167 /* [in] */ ULONG32 size,
168 /* [optional][out] */ ULONG32 *done)
169{
170 assert(false);
171 return E_NOTIMPL;
172}
173
174HRESULT STDMETHODCALLTYPE
175DumpDataTarget::GetTLSValue(
176 /* [in] */ ULONG32 threadID,
177 /* [in] */ ULONG32 index,
178 /* [out] */ CLRDATA_ADDRESS* value)
179{
180 assert(false);
181 return E_NOTIMPL;
182}
183
184HRESULT STDMETHODCALLTYPE
185DumpDataTarget::SetTLSValue(
186 /* [in] */ ULONG32 threadID,
187 /* [in] */ ULONG32 index,
188 /* [in] */ CLRDATA_ADDRESS value)
189{
190 assert(false);
191 return E_NOTIMPL;
192}
193
194HRESULT STDMETHODCALLTYPE
195DumpDataTarget::GetCurrentThreadID(
196 /* [out] */ ULONG32* threadID)
197{
198 assert(false);
199 return E_NOTIMPL;
200}
201
202HRESULT STDMETHODCALLTYPE
203DumpDataTarget::GetThreadContext(
204 /* [in] */ ULONG32 threadID,
205 /* [in] */ ULONG32 contextFlags,
206 /* [in] */ ULONG32 contextSize,
207 /* [out, size_is(contextSize)] */ PBYTE context)
208{
209 assert(m_crashInfo != nullptr);
210 if (contextSize < sizeof(CONTEXT))
211 {
212 assert(false);
213 return E_INVALIDARG;
214 }
215 memset(context, 0, contextSize);
216 for (const ThreadInfo* thread : m_crashInfo->Threads())
217 {
218 if (thread->Tid() == threadID)
219 {
220 thread->GetThreadContext(contextFlags, reinterpret_cast<CONTEXT*>(context));
221 return S_OK;
222 }
223 }
224 return E_FAIL;
225}
226
227HRESULT STDMETHODCALLTYPE
228DumpDataTarget::SetThreadContext(
229 /* [in] */ ULONG32 threadID,
230 /* [in] */ ULONG32 contextSize,
231 /* [out, size_is(contextSize)] */ PBYTE context)
232{
233 assert(false);
234 return E_NOTIMPL;
235}
236
237HRESULT STDMETHODCALLTYPE
238DumpDataTarget::Request(
239 /* [in] */ ULONG32 reqCode,
240 /* [in] */ ULONG32 inBufferSize,
241 /* [size_is][in] */ BYTE *inBuffer,
242 /* [in] */ ULONG32 outBufferSize,
243 /* [size_is][out] */ BYTE *outBuffer)
244{
245 assert(false);
246 return E_NOTIMPL;
247}
248