| 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 | // Keep in sync with https://github.com/dotnet/corert/blob/master/src/Native/ObjWriter/cordebuginfo.h |
| 7 | // |
| 8 | |
| 9 | /**********************************************************************************/ |
| 10 | // DebugInfo types shared by JIT-EE interface and EE-Debugger interface |
| 11 | |
| 12 | class ICorDebugInfo |
| 13 | { |
| 14 | public: |
| 15 | /*----------------------------- Boundary-info ---------------------------*/ |
| 16 | |
| 17 | enum MappingTypes |
| 18 | { |
| 19 | NO_MAPPING = -1, |
| 20 | PROLOG = -2, |
| 21 | EPILOG = -3, |
| 22 | MAX_MAPPING_VALUE = -3 // Sentinal value. This should be set to the largest magnitude value in the enum |
| 23 | // so that the compression routines know the enum's range. |
| 24 | }; |
| 25 | |
| 26 | enum BoundaryTypes |
| 27 | { |
| 28 | NO_BOUNDARIES = 0x00, // No implicit boundaries |
| 29 | STACK_EMPTY_BOUNDARIES = 0x01, // Boundary whenever the IL evaluation stack is empty |
| 30 | NOP_BOUNDARIES = 0x02, // Before every CEE_NOP instruction |
| 31 | CALL_SITE_BOUNDARIES = 0x04, // Before every CEE_CALL, CEE_CALLVIRT, etc instruction |
| 32 | |
| 33 | // Set of boundaries that debugger should always reasonably ask the JIT for. |
| 34 | DEFAULT_BOUNDARIES = STACK_EMPTY_BOUNDARIES | NOP_BOUNDARIES | CALL_SITE_BOUNDARIES |
| 35 | }; |
| 36 | |
| 37 | // Note that SourceTypes can be OR'd together - it's possible that |
| 38 | // a sequence point will also be a stack_empty point, and/or a call site. |
| 39 | // The debugger will check to see if a boundary offset's source field & |
| 40 | // SEQUENCE_POINT is true to determine if the boundary is a sequence point. |
| 41 | |
| 42 | enum SourceTypes |
| 43 | { |
| 44 | SOURCE_TYPE_INVALID = 0x00, // To indicate that nothing else applies |
| 45 | SEQUENCE_POINT = 0x01, // The debugger asked for it. |
| 46 | STACK_EMPTY = 0x02, // The stack is empty here |
| 47 | CALL_SITE = 0x04, // This is a call site. |
| 48 | NATIVE_END_OFFSET_UNKNOWN = 0x08, // Indicates a epilog endpoint |
| 49 | CALL_INSTRUCTION = 0x10 // The actual instruction of a call. |
| 50 | |
| 51 | }; |
| 52 | |
| 53 | struct OffsetMapping |
| 54 | { |
| 55 | DWORD nativeOffset; |
| 56 | DWORD ilOffset; |
| 57 | SourceTypes source; // The debugger needs this so that |
| 58 | // we don't put Edit and Continue breakpoints where |
| 59 | // the stack isn't empty. We can put regular breakpoints |
| 60 | // there, though, so we need a way to discriminate |
| 61 | // between offsets. |
| 62 | }; |
| 63 | |
| 64 | /*------------------------------ Var-info -------------------------------*/ |
| 65 | |
| 66 | // Note: The debugger needs to target register numbers on platforms other than which the debugger itself |
| 67 | // is running. To this end it maintains its own values for REGNUM_SP and REGNUM_AMBIENT_SP across multiple |
| 68 | // platforms. So any change here that may effect these values should be reflected in the definitions |
| 69 | // contained in debug/inc/DbgIPCEvents.h. |
| 70 | enum RegNum |
| 71 | { |
| 72 | #ifdef _TARGET_X86_ |
| 73 | REGNUM_EAX, |
| 74 | REGNUM_ECX, |
| 75 | REGNUM_EDX, |
| 76 | REGNUM_EBX, |
| 77 | REGNUM_ESP, |
| 78 | REGNUM_EBP, |
| 79 | REGNUM_ESI, |
| 80 | REGNUM_EDI, |
| 81 | #elif _TARGET_ARM_ |
| 82 | REGNUM_R0, |
| 83 | REGNUM_R1, |
| 84 | REGNUM_R2, |
| 85 | REGNUM_R3, |
| 86 | REGNUM_R4, |
| 87 | REGNUM_R5, |
| 88 | REGNUM_R6, |
| 89 | REGNUM_R7, |
| 90 | REGNUM_R8, |
| 91 | REGNUM_R9, |
| 92 | REGNUM_R10, |
| 93 | REGNUM_R11, |
| 94 | REGNUM_R12, |
| 95 | REGNUM_SP, |
| 96 | REGNUM_LR, |
| 97 | REGNUM_PC, |
| 98 | #elif _TARGET_ARM64_ |
| 99 | REGNUM_X0, |
| 100 | REGNUM_X1, |
| 101 | REGNUM_X2, |
| 102 | REGNUM_X3, |
| 103 | REGNUM_X4, |
| 104 | REGNUM_X5, |
| 105 | REGNUM_X6, |
| 106 | REGNUM_X7, |
| 107 | REGNUM_X8, |
| 108 | REGNUM_X9, |
| 109 | REGNUM_X10, |
| 110 | REGNUM_X11, |
| 111 | REGNUM_X12, |
| 112 | REGNUM_X13, |
| 113 | REGNUM_X14, |
| 114 | REGNUM_X15, |
| 115 | REGNUM_X16, |
| 116 | REGNUM_X17, |
| 117 | REGNUM_X18, |
| 118 | REGNUM_X19, |
| 119 | REGNUM_X20, |
| 120 | REGNUM_X21, |
| 121 | REGNUM_X22, |
| 122 | REGNUM_X23, |
| 123 | REGNUM_X24, |
| 124 | REGNUM_X25, |
| 125 | REGNUM_X26, |
| 126 | REGNUM_X27, |
| 127 | REGNUM_X28, |
| 128 | REGNUM_FP, |
| 129 | REGNUM_LR, |
| 130 | REGNUM_SP, |
| 131 | REGNUM_PC, |
| 132 | #elif _TARGET_AMD64_ |
| 133 | REGNUM_RAX, |
| 134 | REGNUM_RCX, |
| 135 | REGNUM_RDX, |
| 136 | REGNUM_RBX, |
| 137 | REGNUM_RSP, |
| 138 | REGNUM_RBP, |
| 139 | REGNUM_RSI, |
| 140 | REGNUM_RDI, |
| 141 | REGNUM_R8, |
| 142 | REGNUM_R9, |
| 143 | REGNUM_R10, |
| 144 | REGNUM_R11, |
| 145 | REGNUM_R12, |
| 146 | REGNUM_R13, |
| 147 | REGNUM_R14, |
| 148 | REGNUM_R15, |
| 149 | #else |
| 150 | PORTABILITY_WARNING("Register numbers not defined on this platform" ) |
| 151 | #endif |
| 152 | REGNUM_COUNT, |
| 153 | REGNUM_AMBIENT_SP, // ambient SP support. Ambient SP is the original SP in the non-BP based frame. |
| 154 | // Ambient SP should not change even if there are push/pop operations in the method. |
| 155 | |
| 156 | #ifdef _TARGET_X86_ |
| 157 | REGNUM_FP = REGNUM_EBP, |
| 158 | REGNUM_SP = REGNUM_ESP, |
| 159 | #elif _TARGET_AMD64_ |
| 160 | REGNUM_SP = REGNUM_RSP, |
| 161 | #elif _TARGET_ARM_ |
| 162 | #ifdef REDHAWK |
| 163 | REGNUM_FP = REGNUM_R7, |
| 164 | #else |
| 165 | REGNUM_FP = REGNUM_R11, |
| 166 | #endif //REDHAWK |
| 167 | #elif _TARGET_ARM64_ |
| 168 | //Nothing to do here. FP is already alloted. |
| 169 | #else |
| 170 | // RegNum values should be properly defined for this platform |
| 171 | REGNUM_FP = 0, |
| 172 | REGNUM_SP = 1, |
| 173 | #endif |
| 174 | |
| 175 | }; |
| 176 | |
| 177 | // VarLoc describes the location of a native variable. Note that currently, VLT_REG_BYREF and VLT_STK_BYREF |
| 178 | // are only used for value types on X64. |
| 179 | |
| 180 | enum VarLocType |
| 181 | { |
| 182 | VLT_REG, // variable is in a register |
| 183 | VLT_REG_BYREF, // address of the variable is in a register |
| 184 | VLT_REG_FP, // variable is in an fp register |
| 185 | VLT_STK, // variable is on the stack (memory addressed relative to the frame-pointer) |
| 186 | VLT_STK_BYREF, // address of the variable is on the stack (memory addressed relative to the frame-pointer) |
| 187 | VLT_REG_REG, // variable lives in two registers |
| 188 | VLT_REG_STK, // variable lives partly in a register and partly on the stack |
| 189 | VLT_STK_REG, // reverse of VLT_REG_STK |
| 190 | VLT_STK2, // variable lives in two slots on the stack |
| 191 | VLT_FPSTK, // variable lives on the floating-point stack |
| 192 | VLT_FIXED_VA, // variable is a fixed argument in a varargs function (relative to VARARGS_HANDLE) |
| 193 | |
| 194 | VLT_COUNT, |
| 195 | VLT_INVALID, |
| 196 | }; |
| 197 | |
| 198 | // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc) |
| 199 | // eg. EAX |
| 200 | // VLT_REG_BYREF -- the specified register contains the address of the variable |
| 201 | // eg. [EAX] |
| 202 | |
| 203 | struct vlReg |
| 204 | { |
| 205 | RegNum vlrReg; |
| 206 | }; |
| 207 | |
| 208 | // VLT_STK -- Any 32 bit value which is on the stack |
| 209 | // eg. [ESP+0x20], or [EBP-0x28] |
| 210 | // VLT_STK_BYREF -- the specified stack location contains the address of the variable |
| 211 | // eg. mov EAX, [ESP+0x20]; [EAX] |
| 212 | |
| 213 | struct vlStk |
| 214 | { |
| 215 | RegNum vlsBaseReg; |
| 216 | signed vlsOffset; |
| 217 | }; |
| 218 | |
| 219 | // VLT_REG_REG -- TYP_LONG with both DWords enregistred |
| 220 | // eg. RBM_EAXEDX |
| 221 | |
| 222 | struct vlRegReg |
| 223 | { |
| 224 | RegNum vlrrReg1; |
| 225 | RegNum vlrrReg2; |
| 226 | }; |
| 227 | |
| 228 | // VLT_REG_STK -- Partly enregistered TYP_LONG |
| 229 | // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] } |
| 230 | |
| 231 | struct vlRegStk |
| 232 | { |
| 233 | RegNum vlrsReg; |
| 234 | struct |
| 235 | { |
| 236 | RegNum ; |
| 237 | signed ; |
| 238 | } ; |
| 239 | }; |
| 240 | |
| 241 | // VLT_STK_REG -- Partly enregistered TYP_LONG |
| 242 | // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX } |
| 243 | |
| 244 | struct vlStkReg |
| 245 | { |
| 246 | struct |
| 247 | { |
| 248 | RegNum vlsrsBaseReg; |
| 249 | signed vlsrsOffset; |
| 250 | } vlsrStk; |
| 251 | RegNum vlsrReg; |
| 252 | }; |
| 253 | |
| 254 | // VLT_STK2 -- Any 64 bit value which is on the stack, |
| 255 | // in 2 successsive DWords. |
| 256 | // eg 2 DWords at [ESP+0x10] |
| 257 | |
| 258 | struct vlStk2 |
| 259 | { |
| 260 | RegNum vls2BaseReg; |
| 261 | signed vls2Offset; |
| 262 | }; |
| 263 | |
| 264 | // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack) |
| 265 | // eg. ST(3). Actually it is ST("FPstkHeigth - vpFpStk") |
| 266 | |
| 267 | struct vlFPstk |
| 268 | { |
| 269 | unsigned vlfReg; |
| 270 | }; |
| 271 | |
| 272 | // VLT_FIXED_VA -- fixed argument of a varargs function. |
| 273 | // The argument location depends on the size of the variable |
| 274 | // arguments (...). Inspecting the VARARGS_HANDLE indicates the |
| 275 | // location of the first arg. This argument can then be accessed |
| 276 | // relative to the position of the first arg |
| 277 | |
| 278 | struct vlFixedVarArg |
| 279 | { |
| 280 | unsigned vlfvOffset; |
| 281 | }; |
| 282 | |
| 283 | // VLT_MEMORY |
| 284 | |
| 285 | struct vlMemory |
| 286 | { |
| 287 | void *rpValue; // pointer to the in-process |
| 288 | // location of the value. |
| 289 | }; |
| 290 | |
| 291 | struct VarLoc |
| 292 | { |
| 293 | VarLocType vlType; |
| 294 | |
| 295 | union |
| 296 | { |
| 297 | ICorDebugInfo::vlReg vlReg; |
| 298 | ICorDebugInfo::vlStk vlStk; |
| 299 | ICorDebugInfo::vlRegReg vlRegReg; |
| 300 | ICorDebugInfo::vlRegStk vlRegStk; |
| 301 | ICorDebugInfo::vlStkReg vlStkReg; |
| 302 | ICorDebugInfo::vlStk2 vlStk2; |
| 303 | ICorDebugInfo::vlFPstk vlFPstk; |
| 304 | ICorDebugInfo::vlFixedVarArg vlFixedVarArg; |
| 305 | ICorDebugInfo::vlMemory vlMemory; |
| 306 | }; |
| 307 | }; |
| 308 | |
| 309 | // This is used to report implicit/hidden arguments |
| 310 | |
| 311 | enum |
| 312 | { |
| 313 | VARARGS_HND_ILNUM = -1, // Value for the CORINFO_VARARGS_HANDLE varNumber |
| 314 | RETBUF_ILNUM = -2, // Pointer to the return-buffer |
| 315 | TYPECTXT_ILNUM = -3, // ParamTypeArg for CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG |
| 316 | |
| 317 | UNKNOWN_ILNUM = -4, // Unknown variable |
| 318 | |
| 319 | MAX_ILNUM = -4 // Sentinal value. This should be set to the largest magnitude value in th enum |
| 320 | // so that the compression routines know the enum's range. |
| 321 | }; |
| 322 | |
| 323 | struct ILVarInfo |
| 324 | { |
| 325 | DWORD startOffset; |
| 326 | DWORD endOffset; |
| 327 | DWORD varNumber; |
| 328 | }; |
| 329 | |
| 330 | struct NativeVarInfo |
| 331 | { |
| 332 | DWORD startOffset; |
| 333 | DWORD endOffset; |
| 334 | DWORD varNumber; |
| 335 | VarLoc loc; |
| 336 | }; |
| 337 | }; |
| 338 | |