summaryrefslogtreecommitdiff
path: root/src/jit/disasm.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/disasm.h')
-rw-r--r--src/jit/disasm.h226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/jit/disasm.h b/src/jit/disasm.h
new file mode 100644
index 0000000000..972243e4dc
--- /dev/null
+++ b/src/jit/disasm.h
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XX XX
+XX DisAsm XX
+XX XX
+XX The dis-assembler to display the native code generated XX
+XX XX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+*/
+
+/*****************************************************************************/
+#ifndef _DIS_H_
+#define _DIS_H_
+/*****************************************************************************/
+#ifdef LATE_DISASM
+
+// free() is deprecated (we should only allocate and free memory through CLR hosting interfaces)
+// and is redefined in clrhost.h to cause a compiler error.
+// We don't call free(), but this function is mentioned in STL headers included by msvcdis.h
+// (and free() is only called by STL functions that we don't use).
+// To avoid the compiler error, but at the same time ensure that we don't accidentally use free(),
+// free() is redefined to cause a runtime error instead of a compile time error.
+#undef free
+#ifdef DEBUG
+#define free(x) assert(false && "Must not call free(). Use a ClrXXX function instead.")
+#endif
+
+#if CHECK_STRUCT_PADDING
+#pragma warning(pop)
+#endif // CHECK_STRUCT_PADDING
+
+#define _OLD_IOSTREAMS
+// This pragma is needed because public\vc\inc\xiosbase contains
+// a static local variable
+#pragma warning(disable : 4640)
+#include "msvcdis.h"
+#pragma warning(default : 4640)
+
+#ifdef _TARGET_XARCH_
+#include "disx86.h"
+#elif defined(_TARGET_ARM64_)
+#include "disarm64.h"
+#else // _TARGET_*
+#error Unsupported or unset target architecture
+#endif
+
+#if CHECK_STRUCT_PADDING
+#pragma warning(push)
+#pragma warning(default : 4820) // 'bytes' bytes padding added after construct 'member_name'
+#endif // CHECK_STRUCT_PADDING
+
+/*****************************************************************************/
+
+#ifdef _HOST_64BIT_
+template <typename T>
+struct SizeTKeyFuncs : LargePrimitiveKeyFuncs<T>
+{
+};
+#else // !_HOST_64BIT_
+template <typename T>
+struct SizeTKeyFuncs : SmallPrimitiveKeyFuncs<T>
+{
+};
+#endif // _HOST_64BIT_
+
+typedef SimplerHashTable<size_t, SizeTKeyFuncs<size_t>, CORINFO_METHOD_HANDLE, JitSimplerHashBehavior>
+ AddrToMethodHandleMap;
+typedef SimplerHashTable<size_t, SizeTKeyFuncs<size_t>, size_t, JitSimplerHashBehavior> AddrToAddrMap;
+
+class Compiler;
+
+class DisAssembler
+{
+public:
+ // Constructor
+ void disInit(Compiler* pComp);
+
+ // Initialize the class for the current method being generated.
+ void disOpenForLateDisAsm(const char* curMethodName, const char* curClassName, PCCOR_SIGNATURE sig);
+
+ // Disassemble a buffer: called after code for a method is generated.
+ void disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCodePtr, size_t coldCodeSize);
+
+ // Register an address to be associated with a method handle.
+ void disSetMethod(size_t addr, CORINFO_METHOD_HANDLE methHnd);
+
+ // Register a relocation address.
+ void disRecordRelocation(size_t relocAddr, size_t targetAddr);
+
+private:
+ /* Address of the hot and cold code blocks to dissasemble */
+ size_t disHotCodeBlock;
+ size_t disColdCodeBlock;
+
+ /* Size of the hot and cold code blocks to dissasemble */
+ size_t disHotCodeSize;
+ size_t disColdCodeSize;
+
+ /* Total code size (simply cached version of disHotCodeSize + disColdCodeSize) */
+ size_t disTotalCodeSize;
+
+ /* Address where the code block is to be loaded */
+ size_t disStartAddr;
+
+ /* Current offset in the code block */
+ size_t disCurOffset;
+
+ /* Size (in bytes) of current dissasembled instruction */
+ size_t disInstSize;
+
+ /* Target address of a jump */
+ size_t disTarget;
+
+ /* temporary buffer for function names */
+ // TODO-Review: there is some issue here where this is never set!
+ char disFuncTempBuf[1024];
+
+ /* Method and class name to output */
+ const char* disCurMethodName;
+ const char* disCurClassName;
+
+ /* flag that signals when replacing a symbol name has been deferred for following callbacks */
+ // TODO-Review: there is some issue here where this is never set to 'true'!
+ bool disHasName;
+
+ /* An array of labels, for jumps, LEAs, etc. There is one element in the array for each byte in the generated code.
+ * That byte is zero if the corresponding byte of generated code is not a label. Otherwise, the value
+ * is a label number.
+ */
+ BYTE* disLabels;
+
+ void DisasmBuffer(FILE* pfile, bool printit);
+
+ /* For the purposes of disassembly, we pretend that the hot and cold sections are linear, and not split.
+ * These functions create this model for the rest of the disassembly code.
+ */
+
+ /* Given a linear offset into the code, find a pointer to the actual code (either in the hot or cold section) */
+ const BYTE* disGetLinearAddr(size_t offset);
+
+ /* Given a linear offset into the code, determine how many bytes are left in the hot or cold buffer the offset
+ * points to */
+ size_t disGetBufferSize(size_t offset);
+
+ // Map of instruction addresses to call target method handles for normal calls.
+ AddrToMethodHandleMap* disAddrToMethodHandleMap;
+ AddrToMethodHandleMap* GetAddrToMethodHandleMap();
+
+ // Map of instruction addresses to call target method handles for JIT helper calls.
+ AddrToMethodHandleMap* disHelperAddrToMethodHandleMap;
+ AddrToMethodHandleMap* GetHelperAddrToMethodHandleMap();
+
+ // Map of relocation addresses to relocation target.
+ AddrToAddrMap* disRelocationMap;
+ AddrToAddrMap* GetRelocationMap();
+
+ const char* disGetMethodFullName(size_t addr);
+
+ FILE* disAsmFile;
+
+ Compiler* disComp;
+
+ bool disDiffable; // 'true' if the output should be diffable (hide or obscure absolute addresses)
+
+ template <typename T>
+ T dspAddr(T addr)
+ {
+ return (addr == 0) ? 0 : (disDiffable ? T(0xD1FFAB1E) : addr);
+ }
+
+ /* Callbacks from msdis */
+
+ static size_t __stdcall disCchAddr(
+ const DIS* pdis, DIS::ADDR addr, __in_ecount(cchMax) wchar_t* wz, size_t cchMax, DWORDLONG* pdwDisp);
+
+ size_t disCchAddrMember(
+ const DIS* pdis, DIS::ADDR addr, __in_ecount(cchMax) wchar_t* wz, size_t cchMax, DWORDLONG* pdwDisp);
+
+ static size_t __stdcall disCchFixup(const DIS* pdis,
+ DIS::ADDR addr,
+ size_t size,
+ __in_ecount(cchMax) wchar_t* wz,
+ size_t cchMax,
+ DWORDLONG* pdwDisp);
+
+ size_t disCchFixupMember(const DIS* pdis,
+ DIS::ADDR addr,
+ size_t size,
+ __in_ecount(cchMax) wchar_t* wz,
+ size_t cchMax,
+ DWORDLONG* pdwDisp);
+
+ static size_t __stdcall disCchRegRel(
+ const DIS* pdis, DIS::REGA reg, DWORD disp, __in_ecount(cchMax) wchar_t* wz, size_t cchMax, DWORD* pdwDisp);
+
+ size_t disCchRegRelMember(
+ const DIS* pdis, DIS::REGA reg, DWORD disp, __in_ecount(cchMax) wchar_t* wz, size_t cchMax, DWORD* pdwDisp);
+
+ static size_t __stdcall disCchReg(const DIS* pdis, DIS::REGA reg, __in_ecount(cchMax) wchar_t* wz, size_t cchMax);
+
+ size_t disCchRegMember(const DIS* pdis, DIS::REGA reg, __in_ecount(cchMax) wchar_t* wz, size_t cchMax);
+
+ /* Disassemble helper */
+
+ size_t CbDisassemble(DIS* pdis,
+ size_t offs,
+ DIS::ADDR addr,
+ const BYTE* pb,
+ size_t cbMax,
+ FILE* pfile,
+ bool findLabels,
+ bool printit = false,
+ bool dispOffs = false,
+ bool dispCodeBytes = false);
+};
+
+/*****************************************************************************/
+#endif // LATE_DISASM
+/*****************************************************************************/
+#endif // _DIS_H_
+/*****************************************************************************/