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 | #ifndef __GCCOVER_H__ |
8 | #define __GCCOVER_H__ |
9 | |
10 | #ifdef HAVE_GCCOVER |
11 | |
12 | /****************************************************************************/ |
13 | /* GCCOverageInfo holds the state of which instructions have been visited by |
14 | a GC and which ones have not */ |
15 | |
16 | #ifdef _MSC_VER |
17 | #pragma warning(push) |
18 | #pragma warning(disable : 4200 ) // zero-sized array |
19 | #endif // _MSC_VER |
20 | |
21 | class GCCoverageInfo { |
22 | public: |
23 | IJitManager::MethodRegionInfo methodRegion; |
24 | BYTE* curInstr; // The last instruction that was able to execute |
25 | MethodDesc* lastMD; // Used to quickly figure out the culprite |
26 | |
27 | // Following 6 variables are for prolog / epilog walking coverage |
28 | ICodeManager* codeMan; // CodeMan for this method |
29 | GCInfoToken gcInfoToken; // gcInfo for this method |
30 | |
31 | Thread* callerThread; // Thread associated with context callerRegs |
32 | T_CONTEXT callerRegs; // register state when method was entered |
33 | unsigned gcCount; // GC count at the time we caputured the regs |
34 | bool doingEpilogChecks; // are we doing epilog unwind checks? (do we care about callerRegs?) |
35 | |
36 | enum { hasExecutedSize = 4 }; |
37 | unsigned hasExecuted[hasExecutedSize]; |
38 | unsigned totalCount; |
39 | |
40 | union |
41 | { |
42 | BYTE savedCode[0]; // really variable sized |
43 | // Note that DAC doesn't marshal the entire byte array automatically. |
44 | // Any client of this field needs to get the TADDR of this field and |
45 | // marshal over the bytes properly. |
46 | }; |
47 | |
48 | // Sloppy bitsets (will wrap, and not threadsafe) but best effort is OK |
49 | // since we just need half decent coverage. |
50 | BOOL IsBitSetForOffset(unsigned offset) { |
51 | unsigned dword = hasExecuted[(offset >> 5) % hasExecutedSize]; |
52 | return(dword & (1 << (offset & 0x1F))); |
53 | } |
54 | |
55 | void SetBitForOffset(unsigned offset) { |
56 | unsigned* dword = &hasExecuted[(offset >> 5) % hasExecutedSize]; |
57 | *dword |= (1 << (offset & 0x1F)) ; |
58 | } |
59 | |
60 | void SprinkleBreakpoints(BYTE * saveAddr, PCODE codeStart, size_t codeSize, size_t regionOffsetAdj, BOOL fZapped); |
61 | |
62 | }; |
63 | |
64 | #ifdef _MSC_VER |
65 | #pragma warning(pop) |
66 | #endif // _MSC_VER |
67 | |
68 | |
69 | #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) |
70 | |
71 | #define INTERRUPT_INSTR 0xF4 // X86 HLT instruction (any 1 byte illegal instruction will do) |
72 | #define INTERRUPT_INSTR_CALL 0xFA // X86 CLI instruction |
73 | #define INTERRUPT_INSTR_PROTECT_RET 0xFB // X86 STI instruction |
74 | |
75 | #elif defined(_TARGET_ARM_) |
76 | |
77 | // 16-bit illegal instructions which will cause exception and cause |
78 | // control to go to GcStress codepath |
79 | #define INTERRUPT_INSTR 0xde00 |
80 | #define INTERRUPT_INSTR_CALL 0xde03 // 0xde01 generates SIGTRAP (breakpoint) instead of SIGILL on Unix |
81 | #define INTERRUPT_INSTR_PROTECT_RET 0xde02 |
82 | |
83 | // 32-bit illegal instructions. It is necessary to replace a 16-bit instruction |
84 | // with a 16-bit illegal instruction, and a 32-bit instruction with a 32-bit |
85 | // illegal instruction, to make GC stress with the "IT" instruction work, since |
86 | // it counts the number of instructions that follow it, so we can't change that |
87 | // number by replacing a 32-bit instruction with a 16-bit illegal instruction |
88 | // followed by 16 bits of junk that might end up being a legal instruction. |
89 | // Use the "Permanently UNDEFINED" section in the "ARM Architecture Reference Manual", |
90 | // section A6.3.4 "Branches and miscellaneous control" table. |
91 | // Note that we write these as a single 32-bit write, not two 16-bit writes, so the values |
92 | // need to be arranged as the ARM decoder wants them, with the high-order halfword first |
93 | // (in little-endian order). |
94 | #define INTERRUPT_INSTR_32 0xa001f7f0 // 0xf7f0a001 |
95 | #define INTERRUPT_INSTR_CALL_32 0xa002f7f0 // 0xf7f0a002 |
96 | #define INTERRUPT_INSTR_PROTECT_RET_32 0xa003f7f0 // 0xf7f0a003 |
97 | |
98 | #elif defined(_TARGET_ARM64_) |
99 | |
100 | // The following encodings are undefined. They fall into section C4.5.8 - Data processing (2 source) of |
101 | // "Arm Architecture Reference Manual ARMv8" |
102 | // |
103 | #define INTERRUPT_INSTR 0xBADC0DE0 |
104 | #define INTERRUPT_INSTR_CALL 0xBADC0DE1 |
105 | #define INTERRUPT_INSTR_PROTECT_RET 0xBADC0DE2 |
106 | |
107 | #endif // _TARGET_* |
108 | |
109 | #endif // HAVE_GCCOVER |
110 | |
111 | #endif // !__GCCOVER_H__ |
112 | |