summaryrefslogtreecommitdiff
path: root/src/vm/gccover.h
blob: b2dedefa315a1b12bd2165fd82dd6cdecd053bb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 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.



#ifndef __GCCOVER_H__
#define __GCCOVER_H__

#ifdef HAVE_GCCOVER

/****************************************************************************/
/* GCCOverageInfo holds the state of which instructions have been visited by
   a GC and which ones have not */

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4200 )  // zero-sized array
#endif // _MSC_VER

class GCCoverageInfo {
public:
    IJitManager::MethodRegionInfo methodRegion;    
    BYTE*         curInstr;         // The last instruction that was able to execute 
    MethodDesc*   lastMD;           // Used to quickly figure out the culprite

        // Following 6 variables are for prolog / epilog walking coverage        
    ICodeManager* codeMan;          // CodeMan for this method
    GCInfoToken gcInfoToken;             // gcInfo for this method

    Thread* callerThread;           // Thread associated with context callerRegs
    T_CONTEXT callerRegs;             // register state when method was entered
    unsigned gcCount;               // GC count at the time we caputured the regs
    bool    doingEpilogChecks;      // are we doing epilog unwind checks? (do we care about callerRegs?)

    enum { hasExecutedSize = 4 };
    unsigned hasExecuted[hasExecutedSize];
    unsigned totalCount;

    union
    {
        BYTE savedCode[0];              // really variable sized
                                        // Note that DAC doesn't marshal the entire byte array automatically.
                                        // Any client of this field needs to get the TADDR of this field and
                                        // marshal over the bytes properly.
    };

    // Sloppy bitsets (will wrap, and not threadsafe) but best effort is OK
    // since we just need half decent coverage.  
    BOOL IsBitSetForOffset(unsigned offset) {
        unsigned dword = hasExecuted[(offset >> 5) % hasExecutedSize];
        return(dword & (1 << (offset & 0x1F)));
    }

    void SetBitForOffset(unsigned offset) {
        unsigned* dword = &hasExecuted[(offset >> 5) % hasExecutedSize];
        *dword |= (1 << (offset & 0x1F)) ;
    }

    void SprinkleBreakpoints(BYTE * saveAddr, PCODE codeStart, size_t codeSize, size_t regionOffsetAdj, BOOL fZapped);

};

#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER


#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)

#define INTERRUPT_INSTR                 0xF4    // X86 HLT instruction (any 1 byte illegal instruction will do)
#define INTERRUPT_INSTR_CALL            0xFA    // X86 CLI instruction 
#define INTERRUPT_INSTR_PROTECT_RET     0xFB    // X86 STI instruction 

#elif defined(_TARGET_ARM_)

// 16-bit illegal instructions which will cause exception and cause 
// control to go to GcStress codepath
#define INTERRUPT_INSTR                 0xde00             
#define INTERRUPT_INSTR_CALL            0xde01             
#define INTERRUPT_INSTR_PROTECT_RET     0xde02      

// 32-bit illegal instructions. It is necessary to replace a 16-bit instruction
// with a 16-bit illegal instruction, and a 32-bit instruction with a 32-bit
// illegal instruction, to make GC stress with the "IT" instruction work, since
// it counts the number of instructions that follow it, so we can't change that
// number by replacing a 32-bit instruction with a 16-bit illegal instruction
// followed by 16 bits of junk that might end up being a legal instruction.
// Use the "Permanently UNDEFINED" section in the "ARM Architecture Reference Manual",
// section A6.3.4 "Branches and miscellaneous control" table.
// Note that we write these as a single 32-bit write, not two 16-bit writes, so the values
// need to be arranged as the ARM decoder wants them, with the high-order halfword first
// (in little-endian order).
#define INTERRUPT_INSTR_32              0xa001f7f0 // 0xf7f0a001
#define INTERRUPT_INSTR_CALL_32         0xa002f7f0 // 0xf7f0a002
#define INTERRUPT_INSTR_PROTECT_RET_32  0xa003f7f0 // 0xf7f0a003

#elif defined(_TARGET_ARM64_)

// The following encodings are undefined. They fall into section C4.5.8 - Data processing (2 source) of 
// "Arm Architecture Reference Manual ARMv8"
//
#define INTERRUPT_INSTR                 0xBADC0DE0
#define INTERRUPT_INSTR_CALL            0xBADC0DE1         
#define INTERRUPT_INSTR_PROTECT_RET     0xBADC0DE2  

#endif // _TARGET_*

#endif // HAVE_GCCOVER

#endif // !__GCCOVER_H__