| 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 | |