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 | // ==++== |
6 | // |
7 | |
8 | // |
9 | // ==--== |
10 | #ifndef __disasm_h__ |
11 | #define __disasm_h__ |
12 | |
13 | #include "sos_stacktrace.h" |
14 | |
15 | struct InfoHdr; |
16 | class GCDump; |
17 | |
18 | |
19 | struct DumpStackFlag |
20 | { |
21 | BOOL fEEonly; |
22 | BOOL fSuppressSrcInfo; |
23 | DWORD_PTR top; |
24 | DWORD_PTR end; |
25 | }; |
26 | |
27 | struct GCEncodingInfo |
28 | { |
29 | LPVOID pvMainFiber; |
30 | LPVOID pvGCTableFiber; |
31 | |
32 | BYTE *table; |
33 | unsigned int methodSize; |
34 | |
35 | char buf[1000]; |
36 | int cch; |
37 | |
38 | SIZE_T ofs; |
39 | |
40 | // When decoding a cold region, set this to the size of the hot region to keep offset |
41 | // calculations working. |
42 | SIZE_T hotSizeToAdd; |
43 | bool fDoneDecoding; |
44 | }; |
45 | |
46 | // Returns: |
47 | // NULL if the EHInfo passed in does not refer to a Typed clause |
48 | // "..." if pEHInfo->isCatchAllHandler is TRUE |
49 | // "TypeName" if pEHInfo is a DACEHInfo* that references type "TypeName". |
50 | // Note: |
51 | // The return is a pointer to a global buffer, therefore this value must |
52 | // be consumed as soon as possible after a call to this function. |
53 | LPCWSTR EHTypedClauseTypeName(const DACEHInfo* pEHInfo); |
54 | |
55 | struct SOSEHInfo |
56 | { |
57 | DACEHInfo *m_pInfos; |
58 | UINT EHCount; |
59 | CLRDATA_ADDRESS methodStart; |
60 | |
61 | SOSEHInfo() { ZeroMemory(this, sizeof(SOSEHInfo)); } |
62 | ~SOSEHInfo() { if (m_pInfos) { delete [] m_pInfos; } } |
63 | |
64 | void FormatForDisassembly(CLRDATA_ADDRESS offSet); |
65 | }; |
66 | |
67 | BOOL IsClonedFinally(DACEHInfo *pEHInfo); |
68 | |
69 | void DumpStackWorker (DumpStackFlag &DSFlag); |
70 | |
71 | void UnassemblyUnmanaged (DWORD_PTR IP, BOOL bSuppressLines); |
72 | |
73 | HRESULT CheckEEDll (); |
74 | |
75 | BOOL GetCalleeSite (DWORD_PTR IP, DWORD_PTR &IPCallee); |
76 | |
77 | void DisasmAndClean (DWORD_PTR &IP, __out_ecount_opt(length) char *line, ULONG length); |
78 | |
79 | INT_PTR GetValueFromExpr(___in __in_z char *ptr, INT_PTR &value); |
80 | |
81 | void NextTerm (__deref_inout_z char *& ptr); |
82 | |
83 | BOOL IsByRef (__deref_inout_z char *& ptr); |
84 | |
85 | BOOL IsTermSep (char ch); |
86 | |
87 | const char * HelperFuncName (size_t IP); |
88 | |
89 | enum eTargetType { ettUnk = 0, ettNative = 1, ettJitHelp = 2, ettStub = 3, ettMD = 4 }; |
90 | |
91 | // GetFinalTarget is based on HandleCall, but avoids printing anything to the output. |
92 | // This is currently only called on x64 |
93 | eTargetType GetFinalTarget(DWORD_PTR callee, DWORD_PTR* finalMDorIP); |
94 | |
95 | #ifdef _MSC_VER |
96 | // SOS is essentially single-threaded. ignore "construction of local static object is not thread-safe" |
97 | #pragma warning(push) |
98 | #pragma warning(disable:4640) |
99 | #endif // _MSC_VER |
100 | |
101 | //----------------------------------------------------------------------------------------- |
102 | // |
103 | // Implementations for the supported target platforms |
104 | // |
105 | //----------------------------------------------------------------------------------------- |
106 | |
107 | #ifndef THUMB_CODE |
108 | #define THUMB_CODE 1 |
109 | #endif |
110 | #define STACKWALK_CONTROLPC_ADJUST_OFFSET 2 |
111 | |
112 | #ifdef SOS_TARGET_X86 |
113 | |
114 | /// X86 Machine specific code |
115 | class X86Machine : public IMachine |
116 | { |
117 | public: |
118 | typedef X86_CONTEXT TGT_CTXT; |
119 | |
120 | static IMachine* GetInstance() |
121 | { static X86Machine s_X86MachineInstance; return &s_X86MachineInstance; } |
122 | |
123 | ULONG GetPlatform() const { return IMAGE_FILE_MACHINE_I386; } |
124 | ULONG GetContextSize() const { return sizeof(X86_CONTEXT); } |
125 | virtual void Unassembly( |
126 | TADDR IPBegin, |
127 | TADDR IPEnd, |
128 | TADDR IPAskedFor, |
129 | TADDR GCStressCodeCopy, |
130 | GCEncodingInfo * pGCEncodingInfo, |
131 | SOSEHInfo *pEHInfo, |
132 | BOOL bSuppressLines, |
133 | BOOL bDisplayOffsets) const; |
134 | virtual void IsReturnAddress( |
135 | TADDR retAddr, |
136 | TADDR* whereCalled) const; |
137 | virtual BOOL GetExceptionContext ( |
138 | TADDR stack, |
139 | TADDR PC, |
140 | TADDR *cxrAddr, |
141 | CROSS_PLATFORM_CONTEXT * cxr, |
142 | TADDR * exrAddr, |
143 | PEXCEPTION_RECORD exr) const; |
144 | |
145 | // retrieve stack pointer, frame pointer, and instruction pointer from the target context |
146 | virtual TADDR GetSP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.X86Context.Esp; } |
147 | virtual TADDR GetBP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.X86Context.Ebp; } |
148 | virtual TADDR GetIP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.X86Context.Eip; } |
149 | |
150 | virtual void FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const; |
151 | virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; |
152 | |
153 | virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } |
154 | virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } |
155 | virtual LPCSTR GetSPName() const { return s_SPName; } |
156 | virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const |
157 | { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); } |
158 | |
159 | virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const; |
160 | |
161 | private: |
162 | X86Machine() {} |
163 | ~X86Machine() {} |
164 | X86Machine(const X86Machine& machine); // undefined |
165 | X86Machine & operator=(const X86Machine&); // undefined |
166 | |
167 | private: |
168 | static LPCSTR s_DumpStackHeading; |
169 | static LPCSTR s_DSOHeading; |
170 | static LPCSTR s_GCRegs[7]; |
171 | static LPCSTR s_SPName; |
172 | }; // class X86Machine |
173 | |
174 | #endif // SOS_TARGET_X86 |
175 | |
176 | |
177 | #ifdef SOS_TARGET_ARM |
178 | |
179 | /// ARM Machine specific code |
180 | class ARMMachine : public IMachine |
181 | { |
182 | public: |
183 | typedef ARM_CONTEXT TGT_CTXT; |
184 | |
185 | static IMachine* GetInstance() |
186 | { return &s_ARMMachineInstance; } |
187 | |
188 | ULONG GetPlatform() const { return IMAGE_FILE_MACHINE_ARMNT; } |
189 | ULONG GetContextSize() const { return sizeof(ARM_CONTEXT); } |
190 | virtual void Unassembly( |
191 | TADDR IPBegin, |
192 | TADDR IPEnd, |
193 | TADDR IPAskedFor, |
194 | TADDR GCStressCodeCopy, |
195 | GCEncodingInfo *pGCEncodingInfo, |
196 | SOSEHInfo *pEHInfo, |
197 | BOOL bSuppressLines, |
198 | BOOL bDisplayOffsets) const; |
199 | virtual void IsReturnAddress( |
200 | TADDR retAddr, |
201 | TADDR* whereCalled) const; |
202 | virtual BOOL GetExceptionContext ( |
203 | TADDR stack, |
204 | TADDR PC, |
205 | TADDR *cxrAddr, |
206 | CROSS_PLATFORM_CONTEXT * cxr, |
207 | TADDR *exrAddr, |
208 | PEXCEPTION_RECORD exr) const; |
209 | |
210 | // retrieve stack pointer, frame pointer, and instruction pointer from the target context |
211 | virtual TADDR GetSP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.ArmContext.Sp; } |
212 | // @ARMTODO: frame pointer |
213 | virtual TADDR GetBP(const CROSS_PLATFORM_CONTEXT & ctx) const { return 0; } |
214 | virtual TADDR GetIP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.ArmContext.Pc; } |
215 | |
216 | virtual void FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const; |
217 | virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; |
218 | |
219 | virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } |
220 | virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } |
221 | virtual LPCSTR GetSPName() const { return s_SPName; } |
222 | virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const |
223 | { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); } |
224 | |
225 | virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const; |
226 | |
227 | private: |
228 | ARMMachine() {} |
229 | ~ARMMachine() {} |
230 | ARMMachine(const ARMMachine& machine); // undefined |
231 | ARMMachine & operator=(const ARMMachine&); // undefined |
232 | |
233 | private: |
234 | static LPCSTR s_DumpStackHeading; |
235 | static LPCSTR s_DSOHeading; |
236 | static LPCSTR s_GCRegs[14]; |
237 | static LPCSTR s_SPName; |
238 | static ARMMachine s_ARMMachineInstance; |
239 | }; // class ARMMachine |
240 | |
241 | #endif // SOS_TARGET_ARM |
242 | |
243 | #ifdef SOS_TARGET_AMD64 |
244 | |
245 | /// AMD64 Machine specific code |
246 | class AMD64Machine : public IMachine |
247 | { |
248 | public: |
249 | typedef AMD64_CONTEXT TGT_CTXT; |
250 | |
251 | static IMachine* GetInstance() |
252 | { static AMD64Machine s_AMD64MachineInstance; return &s_AMD64MachineInstance; } |
253 | |
254 | ULONG GetPlatform() const { return IMAGE_FILE_MACHINE_AMD64; } |
255 | ULONG GetContextSize() const { return sizeof(AMD64_CONTEXT); } |
256 | |
257 | virtual void Unassembly( |
258 | TADDR IPBegin, |
259 | TADDR IPEnd, |
260 | TADDR IPAskedFor, |
261 | TADDR GCStressCodeCopy, |
262 | GCEncodingInfo *pGCEncodingInfo, |
263 | SOSEHInfo *pEHInfo, |
264 | BOOL bSuppressLines, |
265 | BOOL bDisplayOffsets) const; |
266 | |
267 | virtual void IsReturnAddress( |
268 | TADDR retAddr, |
269 | TADDR* whereCalled) const; |
270 | |
271 | virtual BOOL GetExceptionContext ( |
272 | TADDR stack, |
273 | TADDR PC, |
274 | TADDR *cxrAddr, |
275 | CROSS_PLATFORM_CONTEXT * cxr, |
276 | TADDR *exrAddr, |
277 | PEXCEPTION_RECORD exr) const; |
278 | |
279 | // retrieve stack pointer, frame pointer, and instruction pointer from the target context |
280 | virtual TADDR GetSP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.Amd64Context.Rsp; } |
281 | virtual TADDR GetBP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.Amd64Context.Rbp; } |
282 | virtual TADDR GetIP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.Amd64Context.Rip; } |
283 | |
284 | virtual void FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const; |
285 | virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; |
286 | |
287 | virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } |
288 | virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } |
289 | virtual LPCSTR GetSPName() const { return s_SPName; } |
290 | virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const |
291 | { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); } |
292 | |
293 | virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool ) const; |
294 | |
295 | private: |
296 | AMD64Machine() {} |
297 | ~AMD64Machine() {} |
298 | AMD64Machine(const AMD64Machine& machine); // undefined |
299 | AMD64Machine & operator=(const AMD64Machine&); // undefined |
300 | |
301 | private: |
302 | static LPCSTR s_DumpStackHeading; |
303 | static LPCSTR s_DSOHeading; |
304 | static LPCSTR s_GCRegs[15]; |
305 | static LPCSTR s_SPName; |
306 | }; // class AMD64Machine |
307 | |
308 | #endif // SOS_TARGET_AMD64 |
309 | |
310 | #ifdef SOS_TARGET_ARM64 |
311 | |
312 | /// ARM64 Machine specific code |
313 | class ARM64Machine : public IMachine |
314 | { |
315 | public: |
316 | typedef ARM64_CONTEXT TGT_CTXT; |
317 | |
318 | static IMachine* GetInstance() |
319 | { static ARM64Machine s_ARM64MachineInstance; return &s_ARM64MachineInstance; } |
320 | |
321 | ULONG GetPlatform() const { return IMAGE_FILE_MACHINE_ARM64; } |
322 | ULONG GetContextSize() const { return sizeof(ARM64_CONTEXT); } |
323 | virtual void Unassembly( |
324 | TADDR IPBegin, |
325 | TADDR IPEnd, |
326 | TADDR IPAskedFor, |
327 | TADDR GCStressCodeCopy, |
328 | GCEncodingInfo *pGCEncodingInfo, |
329 | SOSEHInfo *pEHInfo, |
330 | BOOL bSuppressLines, |
331 | BOOL bDisplayOffsets) const; |
332 | virtual void IsReturnAddress( |
333 | TADDR retAddr, |
334 | TADDR* whereCalled) const; |
335 | virtual BOOL GetExceptionContext ( |
336 | TADDR stack, |
337 | TADDR PC, |
338 | TADDR *cxrAddr, |
339 | CROSS_PLATFORM_CONTEXT * cxr, |
340 | TADDR *exrAddr, |
341 | PEXCEPTION_RECORD exr) const; |
342 | |
343 | // retrieve stack pointer, frame pointer, and instruction pointer from the target context |
344 | virtual TADDR GetSP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.Arm64Context.Sp; } |
345 | virtual TADDR GetBP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.Arm64Context.Fp; } |
346 | virtual TADDR GetIP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.Arm64Context.Pc; } |
347 | |
348 | virtual void FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const; |
349 | virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; |
350 | |
351 | virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } |
352 | virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } |
353 | virtual LPCSTR GetSPName() const { return s_SPName; } |
354 | virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const |
355 | { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs);} |
356 | |
357 | virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const; |
358 | |
359 | private: |
360 | ARM64Machine() {} |
361 | ~ARM64Machine() {} |
362 | ARM64Machine(const ARM64Machine& machine); // undefined |
363 | ARM64Machine & operator=(const ARM64Machine&); // undefined |
364 | |
365 | static LPCSTR s_DumpStackHeading; |
366 | static LPCSTR s_DSOHeading; |
367 | static LPCSTR s_GCRegs[28]; |
368 | static LPCSTR s_SPName; |
369 | |
370 | }; // class ARM64Machine |
371 | |
372 | #endif // SOS_TARGET_ARM64 |
373 | #ifdef _MSC_VER |
374 | #pragma warning(pop) |
375 | #endif // _MSC_VER |
376 | |
377 | |
378 | // |
379 | // Inline methods |
380 | // |
381 | |
382 | |
383 | #ifdef SOS_TARGET_X86 |
384 | inline void X86Machine::FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const |
385 | { |
386 | TGT_CTXT& src = *(TGT_CTXT*) srcCtx; |
387 | dest->StackOffset = src.Esp; |
388 | dest->FrameOffset = src.Ebp; |
389 | dest->InstructionOffset = src.Eip; |
390 | } |
391 | |
392 | inline void X86Machine::FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx /*= 0*/) const |
393 | { |
394 | TGT_CTXT* dest = (TGT_CTXT*)destCtx + idx; |
395 | *dest = *(TGT_CTXT*)srcCtx; |
396 | } |
397 | #endif // SOS_TARGET_X86 |
398 | |
399 | |
400 | #ifdef SOS_TARGET_ARM |
401 | inline void ARMMachine::FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const |
402 | { |
403 | TGT_CTXT& src = *(TGT_CTXT*) srcCtx; |
404 | dest->StackOffset = src.Sp; |
405 | // @ARMTODO: frame pointer - keep in sync with ARMMachine::GetBP |
406 | dest->FrameOffset = 0; |
407 | dest->InstructionOffset = src.Pc; |
408 | } |
409 | |
410 | inline void ARMMachine::FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx /*= 0*/) const |
411 | { |
412 | TGT_CTXT* dest = (TGT_CTXT*)destCtx + idx; |
413 | *dest = *(TGT_CTXT*)srcCtx; |
414 | } |
415 | #endif // SOS_TARGET_ARM |
416 | |
417 | |
418 | #ifdef SOS_TARGET_AMD64 |
419 | inline void AMD64Machine::FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const |
420 | { |
421 | TGT_CTXT& src = *(TGT_CTXT*) srcCtx; |
422 | dest->StackOffset = src.Rsp; |
423 | dest->FrameOffset = src.Rbp; |
424 | dest->InstructionOffset = src.Rip; |
425 | } |
426 | |
427 | inline void AMD64Machine::FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx /*= 0*/) const |
428 | { |
429 | TGT_CTXT* dest = (TGT_CTXT*)destCtx + idx; |
430 | *dest = *(TGT_CTXT*)srcCtx; |
431 | } |
432 | #endif // SOS_TARGET_AMD64 |
433 | |
434 | #ifdef SOS_TARGET_ARM64 |
435 | inline void ARM64Machine::FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const |
436 | { |
437 | TGT_CTXT& src = *(TGT_CTXT*) srcCtx; |
438 | dest->StackOffset = src.Sp; |
439 | dest->FrameOffset = src.Fp; |
440 | dest->InstructionOffset = src.Pc; |
441 | } |
442 | |
443 | inline void ARM64Machine::FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx /*= 0*/) const |
444 | { |
445 | TGT_CTXT* dest = (TGT_CTXT*)destCtx + idx; |
446 | *dest = *(TGT_CTXT*)srcCtx; |
447 | } |
448 | #endif // SOS_TARGET_ARM64 |
449 | |
450 | #endif // __disasm_h__ |
451 | |