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 #ifndef _GCINFO_H_ 7 #define _GCINFO_H_ 8 /*****************************************************************************/ 9 10 // Keep definitions in this file in sync with Nutc\UTC\gcinfo.h 11 12 #ifdef _TARGET_ARM_ 13 14 #define NUM_PRESERVED_REGS 9 15 16 enum RegMask 17 { 18 RBM_R0 = 0x0001, 19 RBM_R1 = 0x0002, 20 RBM_R2 = 0x0004, 21 RBM_R3 = 0x0008, 22 RBM_R4 = 0x0010, // callee saved 23 RBM_R5 = 0x0020, // callee saved 24 RBM_R6 = 0x0040, // callee saved 25 RBM_R7 = 0x0080, // callee saved 26 RBM_R8 = 0x0100, // callee saved 27 RBM_R9 = 0x0200, // callee saved 28 RBM_R10 = 0x0400, // callee saved 29 RBM_R11 = 0x0800, // callee saved 30 RBM_R12 = 0x1000, 31 RBM_SP = 0x2000, 32 RBM_LR = 0x4000, // callee saved, but not valid to be alive across a call! 33 RBM_PC = 0x8000, 34 RBM_RETVAL = RBM_R0, 35 RBM_CALLEE_SAVED_REGS = (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_LR), 36 RBM_CALLEE_SAVED_REG_COUNT = 9, 37 // Special case: LR is callee saved, but may not appear as a live GC ref except 38 // in the leaf frame because calls will trash it. Therefore, we ALSO consider 39 // it a scratch register. 40 RBM_SCRATCH_REGS = (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R12|RBM_LR), 41 RBM_SCRATCH_REG_COUNT = 6, 42 }; 43 44 enum RegNumber 45 { 46 RN_R0 = 0, 47 RN_R1 = 1, 48 RN_R2 = 2, 49 RN_R3 = 3, 50 RN_R4 = 4, 51 RN_R5 = 5, 52 RN_R6 = 6, 53 RN_R7 = 7, 54 RN_R8 = 8, 55 RN_R9 = 9, 56 RN_R10 = 10, 57 RN_R11 = 11, 58 RN_R12 = 12, 59 RN_SP = 13, 60 RN_LR = 14, 61 RN_PC = 15, 62 63 RN_NONE = 16, 64 }; 65 66 enum CalleeSavedRegNum 67 { 68 CSR_NUM_R4 = 0x00, 69 CSR_NUM_R5 = 0x01, 70 CSR_NUM_R6 = 0x02, 71 CSR_NUM_R7 = 0x03, 72 CSR_NUM_R8 = 0x04, 73 CSR_NUM_R9 = 0x05, 74 CSR_NUM_R10 = 0x06, 75 CSR_NUM_R11 = 0x07, 76 // NOTE: LR is omitted because it may not be live except as a 'scratch' reg 77 }; 78 79 enum CalleeSavedRegMask 80 { 81 CSR_MASK_NONE = 0x00, 82 CSR_MASK_R4 = 0x001, 83 CSR_MASK_R5 = 0x002, 84 CSR_MASK_R6 = 0x004, 85 CSR_MASK_R7 = 0x008, 86 CSR_MASK_R8 = 0x010, 87 CSR_MASK_R9 = 0x020, 88 CSR_MASK_R10 = 0x040, 89 CSR_MASK_R11 = 0x080, 90 CSR_MASK_LR = 0x100, 91 92 CSR_MASK_ALL = 0x1ff, 93 CSR_MASK_HIGHEST = 0x100, 94 }; 95 96 enum ScratchRegNum 97 { 98 SR_NUM_R0 = 0x00, 99 SR_NUM_R1 = 0x01, 100 SR_NUM_R2 = 0x02, 101 SR_NUM_R3 = 0x03, 102 SR_NUM_R12 = 0x04, 103 SR_NUM_LR = 0x05, 104 }; 105 106 enum ScratchRegMask 107 { 108 SR_MASK_NONE = 0x00, 109 SR_MASK_R0 = 0x01, 110 SR_MASK_R1 = 0x02, 111 SR_MASK_R2 = 0x04, 112 SR_MASK_R3 = 0x08, 113 SR_MASK_R12 = 0x10, 114 SR_MASK_LR = 0x20, 115 }; 116 117 #elif defined(_TARGET_ARM64_) 118 119 enum RegMask 120 { 121 RBM_NONE = 0, 122 123 RBM_X0 = 0x00000001, 124 RBM_X1 = 0x00000002, 125 RBM_X2 = 0x00000004, 126 RBM_X3 = 0x00000008, 127 RBM_X4 = 0x00000010, 128 RBM_X5 = 0x00000020, 129 RBM_X6 = 0x00000040, 130 RBM_X7 = 0x00000080, 131 RBM_X8 = 0x00000100, // ARM64TODO: ARM64 ABI: indirect result register 132 RBM_X9 = 0x00000200, 133 RBM_X10 = 0x00000400, 134 RBM_X11 = 0x00000800, 135 RBM_X12 = 0x00001000, 136 RBM_X13 = 0x00002000, 137 RBM_X14 = 0x00004000, 138 RBM_X15 = 0x00008000, 139 140 RBM_XIP0 = 0x00010000, // This one is occasionally used as a scratch register (but can be destroyed by branching or a call) 141 RBM_XIP1 = 0x00020000, // This one may be also used as a scratch register (but can be destroyed by branching or a call) 142 RBM_XPR = 0x00040000, 143 144 RBM_X19 = 0x00080000, // RA_CALLEESAVE 145 RBM_X20 = 0x00100000, // RA_CALLEESAVE 146 RBM_X21 = 0x00200000, // RA_CALLEESAVE 147 RBM_X22 = 0x00400000, // RA_CALLEESAVE 148 RBM_X23 = 0x00800000, // RA_CALLEESAVE 149 RBM_X24 = 0x01000000, // RA_CALLEESAVE 150 RBM_X25 = 0x02000000, // RA_CALLEESAVE 151 RBM_X26 = 0x04000000, // RA_CALLEESAVE 152 RBM_X27 = 0x08000000, // RA_CALLEESAVE 153 RBM_X28 = 0x10000000, // RA_CALLEESAVE 154 155 RBM_FP = 0x20000000, 156 RBM_LR = 0x40000000, 157 RBM_SP = 0x80000000, 158 159 RBM_RETVAL = RBM_X8, 160 // Note: Callee saved regs: X19-X28; FP and LR are treated as callee-saved in unwinding code 161 RBM_CALLEE_SAVED_REG_COUNT = 12, 162 163 // Scratch regs: X0-X15, XIP0, XIP1, LR 164 RBM_SCRATCH_REG_COUNT = 19, 165 }; 166 167 #define NUM_PRESERVED_REGS RBM_CALLEE_SAVED_REG_COUNT 168 169 // Number of the callee-saved registers stored in the fixed header 170 #define NUM_PRESERVED_REGS_LOW 9 171 #define MASK_PRESERVED_REGS_LOW ((1 << NUM_PRESERVED_REGS_LOW) - 1) 172 173 enum RegNumber 174 { 175 RN_X0 = 0, 176 RN_X1 = 1, 177 RN_X2 = 2, 178 RN_X3 = 3, 179 RN_X4 = 4, 180 RN_X5 = 5, 181 RN_X6 = 6, 182 RN_X7 = 7, 183 RN_X8 = 8, // indirect result register 184 RN_X9 = 9, 185 RN_X10 = 10, 186 RN_X11 = 11, 187 RN_X12 = 12, 188 RN_X13 = 13, 189 RN_X14 = 14, 190 RN_X15 = 15, 191 192 RN_XIP0 = 16, 193 RN_XIP1 = 17, 194 RN_XPR = 18, 195 196 RN_X19 = 19, // RA_CALLEESAVE 197 RN_X20 = 20, // RA_CALLEESAVE 198 RN_X21 = 21, // RA_CALLEESAVE 199 RN_X22 = 22, // RA_CALLEESAVE 200 RN_X23 = 23, // RA_CALLEESAVE 201 RN_X24 = 24, // RA_CALLEESAVE 202 RN_X25 = 25, // RA_CALLEESAVE 203 RN_X26 = 26, // RA_CALLEESAVE 204 RN_X27 = 27, // RA_CALLEESAVE 205 RN_X28 = 28, // RA_CALLEESAVE 206 207 RN_FP = 29, 208 RN_LR = 30, 209 RN_SP = 31, 210 211 RN_NONE = 32, 212 }; 213 214 enum CalleeSavedRegNum 215 { 216 // NOTE: LR is omitted because it may not be live except as a 'scratch' reg 217 CSR_NUM_X19 = 1, 218 CSR_NUM_X20 = 2, 219 CSR_NUM_X21 = 3, 220 CSR_NUM_X22 = 4, 221 CSR_NUM_X23 = 5, 222 CSR_NUM_X24 = 6, 223 CSR_NUM_X25 = 7, 224 CSR_NUM_X26 = 8, 225 CSR_NUM_X27 = 9, 226 CSR_NUM_X28 = 10, 227 CSR_NUM_FP = 11, 228 CSR_NUM_NONE = 12, 229 }; 230 231 enum CalleeSavedRegMask 232 { 233 CSR_MASK_NONE = 0x00, 234 // LR is placed here to reduce the frequency of the long encoding 235 CSR_MASK_LR = 0x001, 236 CSR_MASK_X19 = 0x002, 237 CSR_MASK_X20 = 0x004, 238 CSR_MASK_X21 = 0x008, 239 CSR_MASK_X22 = 0x010, 240 CSR_MASK_X23 = 0x020, 241 CSR_MASK_X24 = 0x040, 242 CSR_MASK_X25 = 0x080, 243 CSR_MASK_X26 = 0x100, 244 CSR_MASK_X27 = 0x200, 245 CSR_MASK_X28 = 0x400, 246 CSR_MASK_FP = 0x800, 247 248 CSR_MASK_ALL = 0xfff, 249 CSR_MASK_HIGHEST = 0x800, 250 }; 251 252 enum ScratchRegNum 253 { 254 SR_NUM_X0 = 0, 255 SR_NUM_X1 = 1, 256 SR_NUM_X2 = 2, 257 SR_NUM_X3 = 3, 258 SR_NUM_X4 = 4, 259 SR_NUM_X5 = 5, 260 SR_NUM_X6 = 6, 261 SR_NUM_X7 = 7, 262 SR_NUM_X8 = 8, 263 SR_NUM_X9 = 9, 264 SR_NUM_X10 = 10, 265 SR_NUM_X11 = 11, 266 SR_NUM_X12 = 12, 267 SR_NUM_X13 = 13, 268 SR_NUM_X14 = 14, 269 SR_NUM_X15 = 15, 270 271 SR_NUM_XIP0 = 16, 272 SR_NUM_XIP1 = 17, 273 SR_NUM_LR = 18, 274 275 SR_NUM_NONE = 19, 276 }; 277 278 enum ScratchRegMask 279 { 280 SR_MASK_NONE = 0x00, 281 SR_MASK_X0 = 0x01, 282 SR_MASK_X1 = 0x02, 283 SR_MASK_X2 = 0x04, 284 SR_MASK_X3 = 0x08, 285 SR_MASK_X4 = 0x10, 286 SR_MASK_X5 = 0x20, 287 SR_MASK_X6 = 0x40, 288 SR_MASK_X7 = 0x80, 289 SR_MASK_X8 = 0x100, 290 SR_MASK_X9 = 0x200, 291 SR_MASK_X10 = 0x400, 292 SR_MASK_X11 = 0x800, 293 SR_MASK_X12 = 0x1000, 294 SR_MASK_X13 = 0x2000, 295 SR_MASK_X14 = 0x4000, 296 SR_MASK_X15 = 0x8000, 297 298 SR_MASK_XIP0 = 0x10000, 299 SR_MASK_XIP1 = 0x20000, 300 SR_MASK_LR = 0x40000, 301 }; 302 303 #else // _TARGET_ARM_ 304 305 #ifdef _TARGET_AMD64_ 306 #define NUM_PRESERVED_REGS 8 307 #else 308 #define NUM_PRESERVED_REGS 4 309 #endif 310 311 enum RegMask 312 { 313 RBM_EAX = 0x0001, 314 RBM_ECX = 0x0002, 315 RBM_EDX = 0x0004, 316 RBM_EBX = 0x0008, // callee saved 317 RBM_ESP = 0x0010, 318 RBM_EBP = 0x0020, // callee saved 319 RBM_ESI = 0x0040, // callee saved 320 RBM_EDI = 0x0080, // callee saved 321 322 RBM_R8 = 0x0100, 323 RBM_R9 = 0x0200, 324 RBM_R10 = 0x0400, 325 RBM_R11 = 0x0800, 326 RBM_R12 = 0x1000, // callee saved 327 RBM_R13 = 0x2000, // callee saved 328 RBM_R14 = 0x4000, // callee saved 329 RBM_R15 = 0x8000, // callee saved 330 331 RBM_RETVAL = RBM_EAX, 332 333 #ifdef _TARGET_AMD64_ 334 RBM_CALLEE_SAVED_REGS = (RBM_EDI|RBM_ESI|RBM_EBX|RBM_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15), 335 RBM_CALLEE_SAVED_REG_COUNT = 8, 336 RBM_SCRATCH_REGS = (RBM_EAX|RBM_ECX|RBM_EDX|RBM_R8|RBM_R9|RBM_R10|RBM_R11), 337 RBM_SCRATCH_REG_COUNT = 7, 338 #else 339 RBM_CALLEE_SAVED_REGS = (RBM_EDI|RBM_ESI|RBM_EBX|RBM_EBP), 340 RBM_CALLEE_SAVED_REG_COUNT = 4, 341 RBM_SCRATCH_REGS = (RBM_EAX|RBM_ECX|RBM_EDX), 342 RBM_SCRATCH_REG_COUNT = 3, 343 #endif // _TARGET_AMD64_ 344 }; 345 346 enum RegNumber 347 { 348 RN_EAX = 0, 349 RN_ECX = 1, 350 RN_EDX = 2, 351 RN_EBX = 3, 352 RN_ESP = 4, 353 RN_EBP = 5, 354 RN_ESI = 6, 355 RN_EDI = 7, 356 RN_R8 = 8, 357 RN_R9 = 9, 358 RN_R10 = 10, 359 RN_R11 = 11, 360 RN_R12 = 12, 361 RN_R13 = 13, 362 RN_R14 = 14, 363 RN_R15 = 15, 364 365 RN_NONE = 16, 366 }; 367 368 enum CalleeSavedRegNum 369 { 370 CSR_NUM_RBX = 0x00, 371 CSR_NUM_RSI = 0x01, 372 CSR_NUM_RDI = 0x02, 373 CSR_NUM_RBP = 0x03, 374 #ifdef _TARGET_AMD64_ 375 CSR_NUM_R12 = 0x04, 376 CSR_NUM_R13 = 0x05, 377 CSR_NUM_R14 = 0x06, 378 CSR_NUM_R15 = 0x07, 379 #endif // _TARGET_AMD64_ 380 }; 381 382 enum CalleeSavedRegMask 383 { 384 CSR_MASK_NONE = 0x00, 385 CSR_MASK_RBX = 0x01, 386 CSR_MASK_RSI = 0x02, 387 CSR_MASK_RDI = 0x04, 388 CSR_MASK_RBP = 0x08, 389 CSR_MASK_R12 = 0x10, 390 CSR_MASK_R13 = 0x20, 391 CSR_MASK_R14 = 0x40, 392 CSR_MASK_R15 = 0x80, 393 394 #ifdef _TARGET_AMD64_ 395 CSR_MASK_ALL = 0xFF, 396 CSR_MASK_HIGHEST = 0x80, 397 #else 398 CSR_MASK_ALL = 0x0F, 399 CSR_MASK_HIGHEST = 0x08, 400 #endif 401 }; 402 403 enum ScratchRegNum 404 { 405 SR_NUM_RAX = 0x00, 406 SR_NUM_RCX = 0x01, 407 SR_NUM_RDX = 0x02, 408 #ifdef _TARGET_AMD64_ 409 SR_NUM_R8 = 0x03, 410 SR_NUM_R9 = 0x04, 411 SR_NUM_R10 = 0x05, 412 SR_NUM_R11 = 0x06, 413 #endif // _TARGET_AMD64_ 414 }; 415 416 enum ScratchRegMask 417 { 418 SR_MASK_NONE = 0x00, 419 SR_MASK_RAX = 0x01, 420 SR_MASK_RCX = 0x02, 421 SR_MASK_RDX = 0x04, 422 SR_MASK_R8 = 0x08, 423 SR_MASK_R9 = 0x10, 424 SR_MASK_R10 = 0x20, 425 SR_MASK_R11 = 0x40, 426 }; 427 428 #endif // _TARGET_ARM_ 429 430 struct GCInfoHeader 431 { 432 private: 433 UInt16 prologSize : 6; // 0 [0:5] // @TODO: define an 'overflow' encoding for big prologs? 434 UInt16 hasFunclets : 1; // 0 [6] 435 UInt16 fixedEpilogSize : 6; // 0 [7] + 1 [0:4] '0' encoding implies that epilog size varies and is encoded for each epilog 436 UInt16 epilogCountSmall : 2; // 1 [5:6] '3' encoding implies the number of epilogs is encoded separately 437 UInt16 hasExtraData : 1; // 1 [7] 1: more data follows (dynamic alignment, GS cookie, common vars, etc.) 438 439 #ifdef _TARGET_ARM_ 440 UInt16 returnKind : 2; // 2 [0:1] one of: MethodReturnKind enum 441 UInt16 ebpFrame : 1; // 2 [2] on x64, this means "has frame pointer and it is RBP", on ARM R7 442 UInt16 epilogAtEnd : 1; // 2 [3] 443 UInt16 hasFrameSize : 1; // 2 [4] 1: frame size is encoded below, 0: frame size is 0 444 UInt16 calleeSavedRegMask : NUM_PRESERVED_REGS; // 2 [5:7] 3 [0:5] 445 UInt16 arm_areParmOrVfpRegsPushed:1; // 3 [6] 1: pushed param reg set (R0-R3) and pushed fp reg start and count are encoded below, 0: no pushed param or fp registers 446 #elif defined (_TARGET_ARM64_) 447 UInt16 returnKind : 2; // 2 [0:1] one of: MethodReturnKind enum 448 UInt16 ebpFrame : 1; // 2 [2] 1: has frame pointer and it is FP 449 UInt16 epilogAtEnd : 1; // 2 [3] 450 UInt16 hasFrameSize : 1; // 2 [4] 1: frame size is encoded below, 0: frame size is 0 451 UInt16 arm64_longCsrMask : 1; // 2 [5] 1: high bits of calleeSavedRegMask are encoded below 452 UInt16 arm64_areParmOrVfpRegsPushed : 1; // 2 [6] 1: pushed param reg count (X0-X7) and pushed fp reg set (D8-D15) are encoded below, 0: no pushed param or fp registers 453 UInt16 arm64_calleeSavedRegMaskLow : NUM_PRESERVED_REGS_LOW; // 2 [7] 3 [0:7] 454 #else 455 UInt8 returnKind : 2; // 2 [0:1] one of: MethodReturnKind enum 456 UInt8 ebpFrame : 1; // 2 [2] on x64, this means "has frame pointer and it is RBP", on ARM R7 457 UInt8 epilogAtEnd : 1; // 2 [3] 458 #ifdef _TARGET_AMD64_ 459 UInt8 hasFrameSize : 1; // 2 [4] 1: frame size is encoded below, 0: frame size is 0 460 UInt8 x64_framePtrOffsetSmall : 2; // 2 [5:6] 00: framePtrOffset = 0x20 461 // 01: framePtrOffset = 0x30 462 // 10: framePtrOffset = 0x40 463 // 11: a variable-length integer 'x64_frameOffset' follows. 464 UInt8 x64_hasSavedXmmRegs : 1; // 2 [7] any saved xmm registers? 465 #endif 466 // X86 X64 467 UInt8 calleeSavedRegMask : NUM_PRESERVED_REGS; // 2 [4:7] 3 [0:7] 468 469 #ifdef _TARGET_X86_ 470 UInt8 x86_argCountLow : 5; // 3 [0-4] expressed in pointer-sized units // @TODO: steal more bits here? 471 UInt8 x86_argCountIsLarge : 1; // 3 [5] if this bit is set, then the high 8 bits are encoded in x86_argCountHigh 472 UInt8 x86_hasStackChanges : 1; // 3 [6] x86-only, !ebpFrame-only, this method has pushes 473 // and pops in it, and a string follows this header 474 // which describes them 475 UInt8 hasFrameSize : 1; // 3 [7] 1: frame size is encoded below, 0: frame size is 0 476 #endif 477 #endif 478 479 // 480 // OPTIONAL FIELDS FOLLOW 481 // 482 // The following values are encoded with variable-length integers on disk, but are decoded into these 483 // fields in memory. 484 // 485 486 // For ARM and ARM64 this field stores the offset of the callee-saved area relative to FP/SP 487 UInt32 frameSize; // expressed in pointer-sized units, only encoded if hasFrameSize==1 488 // OPTIONAL: only encoded if returnKind = MRK_ReturnsToNative 489 UInt32 reversePinvokeFrameOffset; // expressed in pointer-sized units away from the frame pointer 490 491 #ifdef _TARGET_AMD64_ 492 // OPTIONAL: only encoded if x64_framePtrOffsetSmall = 11 493 // 494 // ENCODING NOTE: In the encoding, the variable-sized unsigned will be 7 less than the total number 495 // of 16-byte units that make up the frame pointer offset. 496 // 497 // In memory, this value will always be set and will always be the total number of 16-byte units that make 498 // up the frame pointer offset. 499 UInt8 x64_framePtrOffset; // expressed in 16-byte unit 500 501 // OPTIONAL: only encoded using a variable-sized unsigned if x64_hasSavedXmmRegs is set. 502 // 503 // An additional optimization is possible because registers xmm0 .. xmm5 should never be saved, 504 // so they are not encoded in the variable-sized unsigned - instead the mask is shifted right 6 bits 505 // for encoding. Thus, any subset of registers xmm6 .. xmm12 can be represented using one byte 506 // - this covers the most frequent cases. 507 // 508 // The shift applies to decoding/encoding only though - the actual header field below uses the 509 // straightforward mapping where bit 0 corresponds to xmm0, bit 1 corresponds to xmm1 and so on. 510 // 511 UInt16 x64_savedXmmRegMask; // which xmm regs were saved 512 #elif defined(_TARGET_X86_) 513 // OPTIONAL: only encoded if x86_argCountIsLarge = 1 514 // NOTE: because we are using pointer-sized units, only 14 bits are required to represent the entire range 515 // that can be expressed by a 'ret NNNN' instruction. Therefore, with 6 in the 'low' field and 8 in the 516 // 'high' field, we are not losing any range here. (Although the need for that full range is debatable.) 517 UInt8 x86_argCountHigh; 518 #elif defined(_TARGET_ARM_) 519 // OPTIONAL: only encoded if arm_areParmOrVfpRegsPushed = 1 520 UInt8 arm_parmRegsPushedSet; 521 UInt8 arm_vfpRegFirstPushed; 522 UInt8 arm_vfpRegPushedCount; 523 #elif defined(_TARGET_ARM64_) 524 // OPTIONAL: high bits of calleeSavedRegMask are encoded only if arm64_longCsrMask = 1; low bits equal to arm64_calleeSavedRegMaskLow 525 UInt16 calleeSavedRegMask; 526 527 // OPTIONAL: only encoded if arm64_areParmOrVfpRegsPushed = 1 528 UInt8 arm64_parmRegsPushedCount; // how many of X0-X7 registers are saved 529 UInt8 arm64_vfpRegsPushedMask; // which of D8-D15 registers are saved 530 #endif 531 532 // 533 // OPTIONAL: only encoded if hasExtraData = 1 534 union 535 { 536 struct 537 { 538 UInt8 logStackAlignment : 4; // [0:3] binary logarithm of frame alignment (3..15) or 0 539 UInt8 hasGSCookie : 1; // [4] 1: frame uses GS cookie 540 UInt8 hasCommonVars : 1; // [5] 1: method has a list of "common vars" 541 // as an optimization for methods with many call sites and variables 542 #if defined(_TARGET_ARM64_) 543 UInt8 FPLRAreOnTop : 1; // [6] 1: FP and LR are saved on top of locals, not at the bottom (see MdmSaveFPAndLRAtTopOfLocalsArea) 544 UInt8 extraDataUnused : 1; // [7] unused bits 545 #else 546 UInt8 extraDataUnused : 2; // [6:7] unused bits 547 #endif 548 #pragma warning(suppress:4201) // nameless struct 549 }; 550 UInt8 extraDataHeader; 551 }; 552 553 // OPTIONAL: only encoded if logStackAlignment != 0 554 UInt8 paramPointerReg; 555 556 // OPTIONAL: only encoded if epilogCountSmall = 3 557 UInt16 epilogCount; 558 559 // OPTIONAL: only encoded if gsCookie = 1 560 UInt32 gsCookieOffset; // expressed in pointer-sized units away from the frame pointer 561 562 // 563 // OPTIONAL: only encoded if hasFunclets = 1 564 // {numFunclets} // encoded as variable-length unsigned 565 // {start-funclet0} // offset from start of previous funclet, encoded as variable-length unsigned 566 // {start-funclet1} // 567 // {start-funclet2} 568 // ... 569 // {sizeof-funclet(N-1)} // numFunclets == N (i.e. there are N+1 sizes here) 570 // ----------------- 571 // {GCInfoHeader-funclet0} // encoded as normal, must not have 'hasFunclets' set. 572 // {GCInfoHeader-funclet1} 573 // ... 574 // {GCInfoHeader-funclet(N-1)} 575 576 // WARNING: 577 // WARNING: Do not add fields to the file-format after the funclet header encodings -- these are decoded 578 // WARNING: recursively and 'in-place' when looking for the info associated with a funclet. Therefore, 579 // WARNING: in that case, we cannot easily continue to decode things associated with the main body 580 // WARNING: GCInfoHeader once we start this recursive decode. 581 // WARNING: 582 583 // ------------------------------------------------------------------------------------------------------- 584 // END of file-encoding-related-fields 585 // ------------------------------------------------------------------------------------------------------- 586 587 // The following fields are not encoded in the file format, they are just used as convenience placeholders 588 // for decode state. 589 UInt32 funcletOffset; // non-zero indicates that this GCInfoHeader is for a funclet 590 591 #if defined(BINDER) 592 public: 593 UInt32 cbThisCodeBody; 594 GCInfoHeader * pNextFunclet; 595 private: 596 ; 597 #endif // BINDER 598 599 600 public: 601 // 602 // CONSTANTS / STATIC STUFF 603 // 604 605 enum MethodReturnKind 606 { 607 MRK_ReturnsScalar = 0, 608 MRK_ReturnsObject = 1, 609 MRK_ReturnsByref = 2, 610 MRK_ReturnsToNative = 3, 611 MRK_Unknown = 4, 612 }; 613 614 enum EncodingConstants 615 { 616 EC_SizeOfFixedHeader = 4, 617 EC_MaxFrameByteSize = 10*1024*1024, 618 EC_MaxReversePInvokeFrameByteOffset = 10*1024*1024, 619 EC_MaxX64FramePtrByteOffset = UInt16_MAX * 0x10, 620 EC_MaxEpilogCountSmall = 3, 621 EC_MaxEpilogCount = 64*1024 - 1, 622 }; 623 624 // 625 // MEMBER FUNCTIONS 626 // 627 InitGCInfoHeader628 void Init() 629 { 630 memset(this, 0, sizeof(GCInfoHeader)); 631 } 632 633 // 634 // SETTERS 635 // 636 SetPrologSizeGCInfoHeader637 void SetPrologSize(UInt32 sizeInBytes) 638 { 639 #if defined (_TARGET_ARM64_) 640 // For arm64 we encode multiples of 4, rather than raw bytes, since instructions are all same size. 641 ASSERT((sizeInBytes & 3) == 0); 642 prologSize = sizeInBytes >> 2; 643 ASSERT(prologSize == sizeInBytes >> 2); 644 #else 645 prologSize = sizeInBytes; 646 ASSERT(prologSize == sizeInBytes); 647 #endif 648 } 649 SetHasFuncletsGCInfoHeader650 void SetHasFunclets(bool fHasFunclets) 651 { 652 hasFunclets = fHasFunclets ? 1 : 0; 653 } 654 PokeFixedEpilogSizeGCInfoHeader655 void PokeFixedEpilogSize(UInt32 sizeInBytes) 656 { 657 #if defined (_TARGET_ARM64_) 658 // For arm64 we encode multiples of 4, rather than raw bytes, since instructions are all same size. 659 ASSERT((sizeInBytes & 3) == 0); 660 fixedEpilogSize = sizeInBytes >> 2; 661 ASSERT(fixedEpilogSize == sizeInBytes >> 2); 662 #else 663 fixedEpilogSize = sizeInBytes; 664 ASSERT(fixedEpilogSize == sizeInBytes); 665 #endif 666 } 667 SetFixedEpilogSizeGCInfoHeader668 void SetFixedEpilogSize(UInt32 sizeInBytes, bool varyingSizes) 669 { 670 if (varyingSizes) 671 fixedEpilogSize = 0; 672 else 673 { 674 ASSERT(sizeInBytes != 0); 675 PokeFixedEpilogSize(sizeInBytes); 676 } 677 } 678 SetEpilogCountGCInfoHeader679 void SetEpilogCount(UInt32 count, bool isAtEnd) 680 { 681 epilogCount = ToUInt16(count); 682 epilogAtEnd = isAtEnd ? 1 : 0; 683 684 ASSERT(epilogCount == count); 685 ASSERT((count == 1) || !isAtEnd); 686 epilogCountSmall = count < EC_MaxEpilogCountSmall ? count : EC_MaxEpilogCountSmall; 687 } 688 SetReturnKindGCInfoHeader689 void SetReturnKind(MethodReturnKind kind) 690 { 691 ASSERT(kind < MRK_Unknown); // not enough bits to encode 'unknown' 692 returnKind = kind; 693 } 694 SetDynamicAlignmentGCInfoHeader695 void SetDynamicAlignment(UInt8 logByteAlignment) 696 { 697 #ifdef _TARGET_X86_ 698 ASSERT(logByteAlignment >= 3); // 4 byte aligned frames 699 #else 700 ASSERT(logByteAlignment >= 4); // 8 byte aligned frames 701 #endif 702 703 hasExtraData = 1; 704 logStackAlignment = logByteAlignment; 705 ASSERT(logStackAlignment == logByteAlignment); 706 paramPointerReg = RN_NONE; 707 } 708 709 #if defined(_TARGET_ARM64_) SetFPLROnTopGCInfoHeader710 void SetFPLROnTop(void) 711 { 712 hasExtraData = 1; 713 FPLRAreOnTop = 1; 714 } 715 #endif 716 SetGSCookieOffsetGCInfoHeader717 void SetGSCookieOffset(UInt32 offsetInBytes) 718 { 719 ASSERT(offsetInBytes != 0); 720 ASSERT(0 == (offsetInBytes % POINTER_SIZE)); 721 hasExtraData = 1; 722 hasGSCookie = 1; 723 gsCookieOffset = offsetInBytes / POINTER_SIZE; 724 } 725 SetHasCommonVarsGCInfoHeader726 void SetHasCommonVars() 727 { 728 hasExtraData = 1; 729 hasCommonVars = 1; 730 } 731 732 void SetParamPointer(RegNumber regNum, UInt32 offsetInBytes, bool isOffsetFromSP = false) 733 { 734 UNREFERENCED_PARAMETER(offsetInBytes); 735 UNREFERENCED_PARAMETER(isOffsetFromSP); 736 ASSERT(HasDynamicAlignment()); // only expected for dynamic aligned frames 737 ASSERT(offsetInBytes==0); // not yet supported 738 739 paramPointerReg = (UInt8)regNum; 740 } 741 742 void SetFramePointer(RegNumber regNum, UInt32 offsetInBytes, bool isOffsetFromSP = false) 743 { 744 UNREFERENCED_PARAMETER(offsetInBytes); 745 UNREFERENCED_PARAMETER(isOffsetFromSP); 746 747 if (regNum == RN_NONE) 748 { 749 ebpFrame = 0; 750 } 751 else 752 { 753 #ifdef _TARGET_ARM_ 754 ASSERT(regNum == RN_R7); 755 #elif defined(_TARGET_AMD64_) || defined(_TARGET_X86_) 756 ASSERT(regNum == RN_EBP); 757 #elif defined(_TARGET_ARM64_) 758 ASSERT(regNum == RN_FP); 759 #else 760 ASSERT(!"NYI"); 761 #endif 762 ebpFrame = 1; 763 } 764 ASSERT(offsetInBytes == 0 || isOffsetFromSP); 765 766 #ifdef _TARGET_AMD64_ 767 if (isOffsetFromSP) 768 offsetInBytes += SKEW_FOR_OFFSET_FROM_SP; 769 770 ASSERT((offsetInBytes % 0x10) == 0); 771 UInt32 offsetInSlots = offsetInBytes / 0x10; 772 if (offsetInSlots >= 3 && offsetInSlots <= 3 + 2) 773 { 774 x64_framePtrOffsetSmall = offsetInSlots - 3; 775 } 776 else 777 { 778 x64_framePtrOffsetSmall = 3; 779 } 780 x64_framePtrOffset = (UInt8)offsetInSlots; 781 ASSERT(x64_framePtrOffset == offsetInSlots); 782 #else 783 ASSERT(offsetInBytes == 0 && !isOffsetFromSP); 784 #endif // _TARGET_AMD64_ 785 } 786 SetFrameSizeGCInfoHeader787 void SetFrameSize(UInt32 frameSizeInBytes) 788 { 789 ASSERT(0 == (frameSizeInBytes % POINTER_SIZE)); 790 frameSize = (frameSizeInBytes / POINTER_SIZE); 791 ASSERT(frameSize == (frameSizeInBytes / POINTER_SIZE)); 792 if (frameSize != 0) 793 { 794 hasFrameSize = 1; 795 } 796 } 797 SetSavedRegsGCInfoHeader798 void SetSavedRegs(CalleeSavedRegMask regMask) 799 { 800 calleeSavedRegMask = (UInt16)regMask; 801 } 802 SetRegSavedGCInfoHeader803 void SetRegSaved(CalleeSavedRegMask regMask) 804 { 805 calleeSavedRegMask |= regMask; 806 } 807 SetReversePinvokeFrameOffsetGCInfoHeader808 void SetReversePinvokeFrameOffset(int offsetInBytes) 809 { 810 ASSERT(HasFramePointer()); 811 ASSERT((offsetInBytes % POINTER_SIZE) == 0); 812 ASSERT(GetReturnKind() == MRK_ReturnsToNative); 813 814 #if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) 815 // The offset can be either positive or negative on ARM and x64. 816 bool isNeg = (offsetInBytes < 0); 817 UInt32 uOffsetInBytes = isNeg ? -offsetInBytes : offsetInBytes; 818 UInt32 uEncodedVal = ((uOffsetInBytes / POINTER_SIZE) << 1) | (isNeg ? 1 : 0); 819 reversePinvokeFrameOffset = uEncodedVal; 820 ASSERT(reversePinvokeFrameOffset == uEncodedVal); 821 #elif defined (_TARGET_X86_) 822 // Use a positive number because it encodes better and 823 // the offset is always negative on x86. 824 ASSERT(offsetInBytes < 0); 825 reversePinvokeFrameOffset = (-offsetInBytes / POINTER_SIZE); 826 ASSERT(reversePinvokeFrameOffset == (UInt32)(-offsetInBytes / POINTER_SIZE)); 827 #else 828 ASSERT(!"NYI"); 829 #endif 830 } 831 832 #ifdef _TARGET_X86_ SetReturnPopSizeGCInfoHeader833 void SetReturnPopSize(UInt32 popSizeInBytes) 834 { 835 ASSERT(0 == (popSizeInBytes % POINTER_SIZE)); 836 ASSERT(GetReturnPopSize() == 0 || GetReturnPopSize() == (int)popSizeInBytes); 837 838 UInt32 argCount = popSizeInBytes / POINTER_SIZE; 839 x86_argCountLow = argCount & 0x1F; 840 if (argCount != x86_argCountLow) 841 { 842 x86_argCountIsLarge = 1; 843 x86_argCountHigh = (UInt8)(argCount >> 5); 844 } 845 } 846 SetHasStackChangesGCInfoHeader847 void SetHasStackChanges() 848 { 849 x86_hasStackChanges = 1; 850 } 851 #endif // _TARGET_X86_ 852 853 #ifdef _TARGET_ARM_ SetParmRegsPushedGCInfoHeader854 void SetParmRegsPushed(ScratchRegMask pushedParmRegs) 855 { 856 // should be a subset of {RO-R3} 857 ASSERT((pushedParmRegs & ~(SR_MASK_R0|SR_MASK_R1|SR_MASK_R2|SR_MASK_R3)) == 0); 858 arm_areParmOrVfpRegsPushed = pushedParmRegs != 0 || arm_vfpRegPushedCount != 0; 859 arm_parmRegsPushedSet = (UInt8)pushedParmRegs; 860 } 861 SetVfpRegsPushedGCInfoHeader862 void SetVfpRegsPushed(UInt8 vfpRegFirstPushed, UInt8 vfpRegPushedCount) 863 { 864 // mrt100.dll really only supports pushing a subinterval of d8-d15 865 // these are the preserved floating point registers according to the ABI spec 866 ASSERT(8 <= vfpRegFirstPushed && vfpRegFirstPushed + vfpRegPushedCount <= 16 || vfpRegPushedCount == 0); 867 arm_vfpRegFirstPushed = vfpRegFirstPushed; 868 arm_vfpRegPushedCount = vfpRegPushedCount; 869 arm_areParmOrVfpRegsPushed = arm_parmRegsPushedSet != 0 || vfpRegPushedCount != 0; 870 } 871 #elif defined(_TARGET_ARM64_) SetParmRegsPushedCountGCInfoHeader872 void SetParmRegsPushedCount(UInt8 parmRegsPushedCount) 873 { 874 // pushed parameter registers are a subset of {R0-R7} 875 ASSERT(parmRegsPushedCount <= 8); 876 arm64_parmRegsPushedCount = parmRegsPushedCount; 877 arm64_areParmOrVfpRegsPushed = (arm64_parmRegsPushedCount != 0) || (arm64_vfpRegsPushedMask != 0); 878 } 879 SetVfpRegsPushedGCInfoHeader880 void SetVfpRegsPushed(UInt8 vfpRegsPushedMask) 881 { 882 arm64_vfpRegsPushedMask = vfpRegsPushedMask; 883 arm64_areParmOrVfpRegsPushed = (arm64_parmRegsPushedCount != 0) || (arm64_vfpRegsPushedMask != 0); 884 } 885 #elif defined(_TARGET_AMD64_) SetSavedXmmRegsGCInfoHeader886 void SetSavedXmmRegs(UInt32 savedXmmRegMask) 887 { 888 // any subset of xmm6-xmm15 may be saved, but no registers in xmm0-xmm5 should be present 889 ASSERT((savedXmmRegMask & 0xffff003f) == 0); 890 x64_hasSavedXmmRegs = savedXmmRegMask != 0; 891 x64_savedXmmRegMask = (UInt16)savedXmmRegMask; 892 } 893 #endif 894 SetFuncletOffsetGCInfoHeader895 void SetFuncletOffset(UInt32 offset) 896 { 897 funcletOffset = offset; 898 } 899 900 // 901 // GETTERS 902 // GetPrologSizeGCInfoHeader903 UInt32 GetPrologSize() 904 { 905 #if defined (_TARGET_ARM64_) 906 return prologSize << 2; 907 #else 908 return prologSize; 909 #endif 910 } 911 HasFuncletsGCInfoHeader912 bool HasFunclets() 913 { 914 return (hasFunclets != 0); 915 } 916 HasVaryingEpilogSizesGCInfoHeader917 bool HasVaryingEpilogSizes() 918 { 919 return fixedEpilogSize == 0; 920 } 921 PeekFixedEpilogSizeGCInfoHeader922 UInt32 PeekFixedEpilogSize() 923 { 924 #if defined (_TARGET_ARM64_) 925 return fixedEpilogSize << 2; 926 #else 927 return fixedEpilogSize; 928 #endif 929 } 930 GetFixedEpilogSizeGCInfoHeader931 UInt32 GetFixedEpilogSize() 932 { 933 ASSERT(!HasVaryingEpilogSizes()); 934 return PeekFixedEpilogSize(); 935 } 936 GetEpilogCountGCInfoHeader937 UInt32 GetEpilogCount() 938 { 939 return epilogCount; 940 } 941 IsEpilogAtEndGCInfoHeader942 bool IsEpilogAtEnd() 943 { 944 return (epilogAtEnd != 0); 945 } 946 GetReturnKindGCInfoHeader947 MethodReturnKind GetReturnKind() 948 { 949 return (MethodReturnKind)returnKind; 950 } 951 ReturnsToNativeGCInfoHeader952 bool ReturnsToNative() 953 { 954 return (GetReturnKind() == MRK_ReturnsToNative); 955 } 956 HasFramePointerGCInfoHeader957 bool HasFramePointer() 958 { 959 return !!ebpFrame; 960 } 961 IsFuncletGCInfoHeader962 bool IsFunclet() 963 { 964 return funcletOffset != 0; 965 } 966 GetFuncletOffsetGCInfoHeader967 UInt32 GetFuncletOffset() 968 { 969 return funcletOffset; 970 } 971 GetPreservedRegsSaveSizeGCInfoHeader972 int GetPreservedRegsSaveSize() const // returned in bytes 973 { 974 UInt32 count = 0; 975 UInt32 mask = calleeSavedRegMask; 976 while (mask != 0) 977 { 978 count += mask & 1; 979 mask >>= 1; 980 } 981 982 return count * POINTER_SIZE; 983 } 984 GetParamPointerRegGCInfoHeader985 int GetParamPointerReg() 986 { 987 return paramPointerReg; 988 } 989 HasDynamicAlignmentGCInfoHeader990 bool HasDynamicAlignment() 991 { 992 return !!logStackAlignment; 993 } 994 GetDynamicAlignmentGCInfoHeader995 UInt32 GetDynamicAlignment() 996 { 997 return 1 << logStackAlignment; 998 } 999 HasGSCookieGCInfoHeader1000 bool HasGSCookie() 1001 { 1002 return hasGSCookie; 1003 } 1004 1005 #if defined(_TARGET_ARM64_) AreFPLROnTopGCInfoHeader1006 bool AreFPLROnTop() 1007 { 1008 return FPLRAreOnTop; 1009 } 1010 #endif 1011 GetGSCookieOffsetGCInfoHeader1012 UInt32 GetGSCookieOffset() 1013 { 1014 ASSERT(hasGSCookie); 1015 return gsCookieOffset * POINTER_SIZE; 1016 } 1017 HasCommonVarsGCInfoHeader1018 bool HasCommonVars() 1019 { 1020 return hasCommonVars; 1021 } 1022 1023 #if defined(RHDUMP) && !defined(_TARGET_AMD64_) 1024 // Due to the wackiness of RhDump, we need this method defined, even though it won't ever be called. GetFramePointerOffsetGCInfoHeader1025 int GetFramePointerOffset() { ASSERT(!"UNREACHABLE"); __assume(0); } 1026 #endif // defined(RHDUMP) && !defined(_TARGET_AMD64_) 1027 1028 #ifdef _TARGET_AMD64_ 1029 static const UInt32 SKEW_FOR_OFFSET_FROM_SP = 0x10; 1030 GetFramePointerOffsetGCInfoHeader1031 int GetFramePointerOffset() // returned in bytes 1032 { 1033 // traditional frames where FP points to the pushed FP have fp offset == 0 1034 if (x64_framePtrOffset == 0) 1035 return 0; 1036 1037 // otherwise it's an x64 style frame where the fp offset is measured from the sp 1038 // at the end of the prolog 1039 int offsetFromSP = GetFramePointerOffsetFromSP(); 1040 1041 int preservedRegsSaveSize = GetPreservedRegsSaveSize(); 1042 1043 // we when called from the binder, rbp isn't set to be a preserved reg, 1044 // when called from the runtime, it is - compensate for this inconsistency 1045 if (IsRegSaved(CSR_MASK_RBP)) 1046 preservedRegsSaveSize -= POINTER_SIZE; 1047 1048 return offsetFromSP - preservedRegsSaveSize - GetFrameSize(); 1049 } 1050 IsFramePointerOffsetFromSPGCInfoHeader1051 bool IsFramePointerOffsetFromSP() 1052 { 1053 return x64_framePtrOffset != 0; 1054 } 1055 GetFramePointerOffsetFromSPGCInfoHeader1056 int GetFramePointerOffsetFromSP() 1057 { 1058 ASSERT(IsFramePointerOffsetFromSP()); 1059 int offsetFromSP; 1060 offsetFromSP = x64_framePtrOffset * 0x10; 1061 ASSERT(offsetFromSP >= SKEW_FOR_OFFSET_FROM_SP); 1062 offsetFromSP -= SKEW_FOR_OFFSET_FROM_SP; 1063 1064 return offsetFromSP; 1065 } 1066 GetFramePointerRegGCInfoHeader1067 int GetFramePointerReg() 1068 { 1069 return RN_EBP; 1070 } 1071 HasSavedXmmRegsGCInfoHeader1072 bool HasSavedXmmRegs() 1073 { 1074 return x64_hasSavedXmmRegs != 0; 1075 } 1076 GetSavedXmmRegMaskGCInfoHeader1077 UInt16 GetSavedXmmRegMask() 1078 { 1079 ASSERT(x64_hasSavedXmmRegs); 1080 return x64_savedXmmRegMask; 1081 } 1082 #elif defined(_TARGET_X86_) GetReturnPopSizeGCInfoHeader1083 int GetReturnPopSize() // returned in bytes 1084 { 1085 if (!x86_argCountIsLarge) 1086 { 1087 return x86_argCountLow * POINTER_SIZE; 1088 } 1089 return ((x86_argCountHigh << 5) | x86_argCountLow) * POINTER_SIZE; 1090 } 1091 HasStackChangesGCInfoHeader1092 bool HasStackChanges() 1093 { 1094 return !!x86_hasStackChanges; 1095 } 1096 #endif 1097 GetFrameSizeGCInfoHeader1098 int GetFrameSize() 1099 { 1100 return frameSize * POINTER_SIZE; 1101 } 1102 1103 GetReversePinvokeFrameOffsetGCInfoHeader1104 int GetReversePinvokeFrameOffset() 1105 { 1106 #if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) 1107 // The offset can be either positive or negative on ARM. 1108 Int32 offsetInBytes; 1109 UInt32 uEncodedVal = reversePinvokeFrameOffset; 1110 bool isNeg = ((uEncodedVal & 1) == 1); 1111 offsetInBytes = (uEncodedVal >> 1) * POINTER_SIZE; 1112 offsetInBytes = isNeg ? -offsetInBytes : offsetInBytes; 1113 return offsetInBytes; 1114 #elif defined(_TARGET_X86_) 1115 // it's always at "EBP - something", so we encode it as a positive 1116 // number and then apply the negative here. 1117 int unsignedOffset = reversePinvokeFrameOffset * POINTER_SIZE; 1118 return -unsignedOffset; 1119 #else 1120 ASSERT(!"NYI"); 1121 #endif 1122 } 1123 GetSavedRegsGCInfoHeader1124 CalleeSavedRegMask GetSavedRegs() 1125 { 1126 return (CalleeSavedRegMask) calleeSavedRegMask; 1127 } 1128 IsRegSavedGCInfoHeader1129 bool IsRegSaved(CalleeSavedRegMask reg) 1130 { 1131 return (0 != (calleeSavedRegMask & reg)); 1132 } 1133 1134 #ifdef _TARGET_ARM_ AreParmRegsPushedGCInfoHeader1135 bool AreParmRegsPushed() 1136 { 1137 return arm_parmRegsPushedSet != 0; 1138 } 1139 ParmRegsPushedCountGCInfoHeader1140 UInt16 ParmRegsPushedCount() 1141 { 1142 UInt8 set = arm_parmRegsPushedSet; 1143 UInt8 count = 0; 1144 while (set != 0) 1145 { 1146 count += set & 1; 1147 set >>= 1; 1148 } 1149 return count; 1150 } 1151 GetVfpRegFirstPushedGCInfoHeader1152 UInt8 GetVfpRegFirstPushed() 1153 { 1154 return arm_vfpRegFirstPushed; 1155 } 1156 GetVfpRegPushedCountGCInfoHeader1157 UInt8 GetVfpRegPushedCount() 1158 { 1159 return arm_vfpRegPushedCount; 1160 } 1161 #elif defined(_TARGET_ARM64_) ParmRegsPushedCountGCInfoHeader1162 UInt8 ParmRegsPushedCount() 1163 { 1164 return arm64_parmRegsPushedCount; 1165 } 1166 GetVfpRegsPushedMaskGCInfoHeader1167 UInt8 GetVfpRegsPushedMask() 1168 { 1169 return arm64_vfpRegsPushedMask; 1170 } 1171 #endif 1172 1173 // 1174 // ENCODING HELPERS 1175 // 1176 #ifndef DACCESS_COMPILE EncodeHeaderGCInfoHeader1177 size_t EncodeHeader(UInt8 * & pDest) 1178 { 1179 #ifdef _DEBUG 1180 UInt8 * pStart = pDest; 1181 #endif // _DEBUG 1182 1183 #if defined(_TARGET_ARM64_) 1184 UInt8 calleeSavedRegMaskHigh = calleeSavedRegMask >> NUM_PRESERVED_REGS_LOW; 1185 arm64_calleeSavedRegMaskLow = calleeSavedRegMask & MASK_PRESERVED_REGS_LOW; 1186 if (calleeSavedRegMaskHigh) 1187 { 1188 arm64_longCsrMask = 1; 1189 } 1190 #endif 1191 1192 size_t size = EC_SizeOfFixedHeader; 1193 if (pDest) 1194 { 1195 memcpy(pDest, this, EC_SizeOfFixedHeader); 1196 pDest += EC_SizeOfFixedHeader; 1197 } 1198 1199 if (hasFrameSize) 1200 size += WriteUnsigned(pDest, frameSize); 1201 1202 if (returnKind == MRK_ReturnsToNative) 1203 size += WriteUnsigned(pDest, reversePinvokeFrameOffset); 1204 1205 #ifdef _TARGET_AMD64_ 1206 if (x64_framePtrOffsetSmall == 0x3) 1207 size += WriteUnsigned(pDest, x64_framePtrOffset); 1208 1209 if (x64_hasSavedXmmRegs) 1210 { 1211 ASSERT((x64_savedXmmRegMask & 0x3f) == 0); 1212 UInt32 encodedValue = x64_savedXmmRegMask >> 6; 1213 size += WriteUnsigned(pDest, encodedValue); 1214 } 1215 #elif defined(_TARGET_X86_) 1216 if (x86_argCountIsLarge) 1217 { 1218 size += 1; 1219 if (pDest) 1220 *pDest++ = x86_argCountHigh; 1221 } 1222 ASSERT(!x86_hasStackChanges || !"NYI -- stack changes for ESP frames"); 1223 #elif defined(_TARGET_ARM_) 1224 if (arm_areParmOrVfpRegsPushed) 1225 { 1226 // we encode a bit field where the low 4 bits represent the pushed parameter register 1227 // set, the next 8 bits are the number of pushed floating point registers, and the highest 1228 // bits are the first pushed floating point register plus 1. 1229 // The 0 encoding means the first floating point register is 8 as this is the most frequent. 1230 UInt32 encodedValue = arm_parmRegsPushedSet | (arm_vfpRegPushedCount << 4); 1231 // usually, the first pushed floating point register is d8 1232 if (arm_vfpRegFirstPushed != 8) 1233 encodedValue |= (arm_vfpRegFirstPushed+1) << (8+4); 1234 1235 size += WriteUnsigned(pDest, encodedValue); 1236 } 1237 #elif defined(_TARGET_ARM64_) 1238 if (calleeSavedRegMaskHigh) 1239 { 1240 size += 1; 1241 if (pDest) 1242 *pDest++ = calleeSavedRegMaskHigh; 1243 } 1244 1245 if (arm64_areParmOrVfpRegsPushed) 1246 { 1247 // At present arm64_parmRegsPushedCount is non-zero only for variadic functions, so place this field higher 1248 UInt32 encodedValue = arm64_vfpRegsPushedMask | (arm64_parmRegsPushedCount << 8); 1249 size += WriteUnsigned(pDest, encodedValue); 1250 } 1251 #endif 1252 1253 // encode dynamic alignment and GS cookie information 1254 if (hasExtraData) 1255 { 1256 size += WriteUnsigned(pDest, extraDataHeader); 1257 } 1258 if (HasDynamicAlignment()) 1259 { 1260 size += WriteUnsigned(pDest, paramPointerReg); 1261 } 1262 if (hasGSCookie) 1263 { 1264 size += WriteUnsigned(pDest, gsCookieOffset); 1265 } 1266 1267 if (epilogCountSmall == EC_MaxEpilogCountSmall) 1268 { 1269 size += WriteUnsigned(pDest, epilogCount); 1270 } 1271 1272 // WARNING: 1273 // WARNING: Do not add fields to the file-format after the funclet header encodings -- these are 1274 // WARNING: decoded recursively and 'in-place' when looking for the info associated with a funclet. 1275 // WARNING: Therefore, in that case, we cannot easily continue to decode things associated with the 1276 // WARNING: main body GCInfoHeader once we start this recursive decode. 1277 // WARNING: 1278 size += EncodeFuncletInfo(pDest); 1279 1280 #ifdef _DEBUG 1281 ASSERT(!pDest || (size == (size_t)(pDest - pStart))); 1282 #endif // _DEBUG 1283 1284 return size; 1285 } 1286 WriteUnsignedGCInfoHeader1287 size_t WriteUnsigned(UInt8 * & pDest, UInt32 value) 1288 { 1289 size_t size = (size_t)VarInt::WriteUnsigned(pDest, value); 1290 pDest = pDest ? (pDest + size) : pDest; 1291 return size; 1292 } 1293 EncodeFuncletInfoGCInfoHeader1294 size_t EncodeFuncletInfo(UInt8 * & pDest) 1295 { 1296 UNREFERENCED_PARAMETER(pDest); 1297 size_t size = 0; 1298 #if defined(BINDER) 1299 if (hasFunclets) 1300 { 1301 UInt32 nFunclets = 0; 1302 for (GCInfoHeader * pCur = pNextFunclet; pCur != NULL; pCur = pCur->pNextFunclet) 1303 nFunclets++; 1304 1305 // first write out the number of funclets 1306 size += WriteUnsigned(pDest, nFunclets); 1307 1308 // cbThisCodeBody is the size, but what we end up encoding is the size of all the code bodies 1309 // except for the last one (because the last one's size can be implicitly figured out by the size 1310 // of the method). So we have to save the size of the 'main body' and not the size of the last 1311 // funclet. In the encoding, this will look like the offset of a given funclet from the start of 1312 // the previous code body. We like relative offsets because they'll encode to be smaller. 1313 for (GCInfoHeader * pCur = this; pCur->pNextFunclet != NULL; pCur = pCur->pNextFunclet) 1314 size += WriteUnsigned(pDest, pCur->cbThisCodeBody); 1315 1316 // now encode all the funclet headers 1317 for (GCInfoHeader * pCur = pNextFunclet; pCur != NULL; pCur = pCur->pNextFunclet) 1318 size += pCur->EncodeHeader(pDest); 1319 } 1320 #else // BINDER 1321 ASSERT(!"NOT REACHABLE"); 1322 #endif // BINDER 1323 return size; 1324 } 1325 #endif // DACCESS_COMPILE 1326 ToUInt16GCInfoHeader1327 UInt16 ToUInt16(UInt32 val) 1328 { 1329 UInt16 result = (UInt16)val; 1330 ASSERT(val == result); 1331 return result; 1332 } 1333 ToUInt8GCInfoHeader1334 UInt8 ToUInt8(UInt32 val) 1335 { 1336 UInt8 result = (UInt8)val; 1337 ASSERT(val == result); 1338 return result; 1339 } 1340 1341 // 1342 // DECODING HELPERS 1343 // 1344 // Returns a pointer to the 'stack change string' on x86. DecodeHeaderGCInfoHeader1345 PTR_UInt8 DecodeHeader(UInt32 methodOffset, PTR_UInt8 pbHeaderEncoding, size_t* pcbHeader) 1346 { 1347 PTR_UInt8 pbStackChangeString = NULL; 1348 1349 TADDR pbTemp = PTR_TO_TADDR(pbHeaderEncoding); 1350 memcpy(this, PTR_READ(pbTemp, EC_SizeOfFixedHeader), EC_SizeOfFixedHeader); 1351 1352 PTR_UInt8 pbDecode = pbHeaderEncoding + EC_SizeOfFixedHeader; 1353 frameSize = hasFrameSize 1354 ? VarInt::ReadUnsigned(pbDecode) 1355 : 0; 1356 1357 reversePinvokeFrameOffset = (returnKind == MRK_ReturnsToNative) 1358 ? VarInt::ReadUnsigned(pbDecode) 1359 : 0; 1360 1361 #ifdef _TARGET_AMD64_ 1362 x64_framePtrOffset = (x64_framePtrOffsetSmall == 0x3) 1363 ? ToUInt8(VarInt::ReadUnsigned(pbDecode)) 1364 : x64_framePtrOffsetSmall + 3; 1365 1366 1367 x64_savedXmmRegMask = 0; 1368 if (x64_hasSavedXmmRegs) 1369 { 1370 UInt32 encodedValue = VarInt::ReadUnsigned(pbDecode); 1371 ASSERT((encodedValue & ~0x3ff) == 0); 1372 x64_savedXmmRegMask = ToUInt16(encodedValue << 6); 1373 } 1374 1375 #elif defined(_TARGET_X86_) 1376 if (x86_argCountIsLarge) 1377 x86_argCountHigh = *pbDecode++; 1378 else 1379 x86_argCountHigh = 0; 1380 1381 if (x86_hasStackChanges) 1382 { 1383 pbStackChangeString = pbDecode; 1384 1385 bool last = false; 1386 while (!last) 1387 { 1388 UInt8 b = *pbDecode++; 1389 // 00111111 {delta} forwarder 1390 // 00dddddd push 1, dddddd = delta 1391 // nnnldddd pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed) 1392 if (b == 0x3F) 1393 { 1394 // 00111111 {delta} forwarder 1395 VarInt::ReadUnsigned(pbDecode); 1396 } 1397 else if (0 != (b & 0xC0)) 1398 { 1399 // nnnldddd pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed) 1400 last = ((b & 0x10) == 0x10); 1401 } 1402 } 1403 } 1404 #elif defined(_TARGET_ARM_) 1405 arm_parmRegsPushedSet = 0; 1406 arm_vfpRegPushedCount = 0; 1407 arm_vfpRegFirstPushed = 0; 1408 if (arm_areParmOrVfpRegsPushed) 1409 { 1410 UInt32 encodedValue = VarInt::ReadUnsigned(pbDecode); 1411 arm_parmRegsPushedSet = encodedValue & 0x0f; 1412 arm_vfpRegPushedCount = (UInt8)(encodedValue >> 4); 1413 UInt32 vfpRegFirstPushed = encodedValue >> (8 + 4); 1414 if (vfpRegFirstPushed == 0) 1415 arm_vfpRegFirstPushed = 8; 1416 else 1417 arm_vfpRegFirstPushed = (UInt8)(vfpRegFirstPushed - 1); 1418 } 1419 #elif defined(_TARGET_ARM64_) 1420 calleeSavedRegMask = arm64_calleeSavedRegMaskLow; 1421 if (arm64_longCsrMask) 1422 { 1423 calleeSavedRegMask |= (*pbDecode++ << NUM_PRESERVED_REGS_LOW); 1424 } 1425 1426 arm64_parmRegsPushedCount = 0; 1427 arm64_vfpRegsPushedMask = 0; 1428 if (arm64_areParmOrVfpRegsPushed) 1429 { 1430 UInt32 encodedValue = VarInt::ReadUnsigned(pbDecode); 1431 arm64_vfpRegsPushedMask = (UInt8)encodedValue; 1432 arm64_parmRegsPushedCount = (UInt8)(encodedValue >> 8); 1433 ASSERT(arm64_parmRegsPushedCount <= 8); 1434 } 1435 #endif 1436 1437 extraDataHeader = hasExtraData ? ToUInt8(VarInt::ReadUnsigned(pbDecode)) : 0; 1438 paramPointerReg = HasDynamicAlignment() ? ToUInt8(VarInt::ReadUnsigned(pbDecode)) : (UInt8)RN_NONE; 1439 gsCookieOffset = hasGSCookie ? VarInt::ReadUnsigned(pbDecode) : 0; 1440 1441 epilogCount = epilogCountSmall < EC_MaxEpilogCountSmall ? epilogCountSmall : ToUInt16(VarInt::ReadUnsigned(pbDecode)); 1442 1443 this->funcletOffset = 0; 1444 if (hasFunclets) 1445 { 1446 // WORKAROUND: Epilog tables are still per-method instead of per-funclet, but we don't deal with 1447 // them here. So we will simply overwrite the funclet's epilogAtEnd and epilogCount 1448 // with the values from the main code body -- these were the values used to generate 1449 // the per-method epilog table, so at least we're consistent with what is encoded. 1450 UInt8 mainEpilogAtEnd = epilogAtEnd; 1451 UInt16 mainEpilogCount = epilogCount; 1452 UInt16 mainFixedEpilogSize = (UInt16) PeekFixedEpilogSize(); 1453 UInt8 mainHasCommonVars = hasCommonVars; 1454 // ------- 1455 1456 int nFunclets = (int)VarInt::ReadUnsigned(pbDecode); 1457 int idxFunclet = -2; 1458 UInt32 offsetFunclet = 0; 1459 // Decode the funclet start offsets, remembering which one is of interest. 1460 UInt32 prevFuncletStart = 0; 1461 for (int i = 0; i < nFunclets; i++) 1462 { 1463 UInt32 offsetThisFunclet = prevFuncletStart + VarInt::ReadUnsigned(pbDecode); 1464 if ((idxFunclet == -2) && (methodOffset < offsetThisFunclet)) 1465 { 1466 idxFunclet = (i - 1); 1467 offsetFunclet = prevFuncletStart; 1468 } 1469 prevFuncletStart = offsetThisFunclet; 1470 } 1471 if ((idxFunclet == -2) && (methodOffset >= prevFuncletStart)) 1472 { 1473 idxFunclet = (nFunclets - 1); 1474 offsetFunclet = prevFuncletStart; 1475 } 1476 1477 // Now decode headers until we find the one we want. Keep decoding if we need to report a size. 1478 if (pcbHeader || (idxFunclet >= 0)) 1479 { 1480 for (int i = 0; i < nFunclets; i++) 1481 { 1482 size_t hdrSize; 1483 if (i == idxFunclet) 1484 { 1485 this->DecodeHeader(methodOffset, pbDecode, &hdrSize); 1486 pbDecode += hdrSize; 1487 this->funcletOffset = offsetFunclet; 1488 if (!pcbHeader) // if nobody is going to look at the header size, we don't need to keep going 1489 break; 1490 } 1491 else 1492 { 1493 // keep decoding into a temp just to get the right header size 1494 GCInfoHeader tmp; 1495 tmp.DecodeHeader(methodOffset, pbDecode, &hdrSize); 1496 pbDecode += hdrSize; 1497 } 1498 } 1499 } 1500 1501 // WORKAROUND: see above 1502 this->epilogAtEnd = mainEpilogAtEnd; 1503 this->epilogCount = mainEpilogCount; 1504 this->PokeFixedEpilogSize(mainFixedEpilogSize); 1505 this->hasCommonVars = mainHasCommonVars; 1506 1507 // ------- 1508 } 1509 1510 // WARNING: 1511 // WARNING: Do not add fields to the file-format after the funclet header encodings -- these are 1512 // WARNING: decoded recursively and 'in-place' when looking for the info associated with a funclet. 1513 // WARNING: Therefore, in that case, we cannot easily continue to decode things associated with the 1514 // WARNING: main body GCInfoHeader once we start this recursive decode. 1515 // WARNING: 1516 1517 if (pcbHeader) 1518 *pcbHeader = pbDecode - pbHeaderEncoding; 1519 1520 return pbStackChangeString; 1521 } 1522 GetFuncletInfoGCInfoHeader1523 void GetFuncletInfo(PTR_UInt8 pbHeaderEncoding, UInt32* pnFuncletsOut, PTR_UInt8* pEncodedFuncletStartOffsets) 1524 { 1525 ASSERT(hasFunclets); 1526 1527 PTR_UInt8 pbDecode = pbHeaderEncoding + EC_SizeOfFixedHeader; 1528 if (hasFrameSize) { VarInt::SkipUnsigned(pbDecode); } 1529 if (returnKind == MRK_ReturnsToNative) { VarInt::SkipUnsigned(pbDecode); } 1530 if (hasExtraData) { VarInt::SkipUnsigned(pbDecode); } 1531 if (HasDynamicAlignment()) { VarInt::SkipUnsigned(pbDecode); } 1532 if (hasGSCookie) { VarInt::SkipUnsigned(pbDecode); } 1533 1534 #ifdef _TARGET_AMD64_ 1535 if (x64_framePtrOffsetSmall == 0x3) { VarInt::SkipUnsigned(pbDecode); } 1536 #elif defined(_TARGET_X86_) 1537 if (x86_argCountIsLarge) 1538 pbDecode++; 1539 1540 if (x86_hasStackChanges) 1541 { 1542 bool last = false; 1543 while (!last) 1544 { 1545 UInt8 b = *pbDecode++; 1546 // 00111111 {delta} forwarder 1547 // 00dddddd push 1, dddddd = delta 1548 // nnnldddd pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed) 1549 if (b == 0x3F) 1550 { 1551 // 00111111 {delta} forwarder 1552 VarInt::SkipUnsigned(pbDecode); 1553 } 1554 else if (0 != (b & 0xC0)) 1555 { 1556 // nnnldddd pop nnn-1, l = last, dddd = delta (nnn=0 and nnn=1 are disallowed) 1557 last = ((b & 0x10) == 0x10); 1558 } 1559 } 1560 } 1561 #elif defined(_TARGET_ARM_) 1562 if (arm_areParmOrVfpRegsPushed) { VarInt::SkipUnsigned(pbDecode); } 1563 #elif defined(_TARGET_ARM64_) 1564 if (arm64_longCsrMask) { pbDecode++; } 1565 if (arm64_areParmOrVfpRegsPushed) { VarInt::SkipUnsigned(pbDecode); } 1566 #endif 1567 1568 *pnFuncletsOut = VarInt::ReadUnsigned(pbDecode); 1569 *pEncodedFuncletStartOffsets = pbDecode; 1570 } 1571 1572 #ifdef BINDER IsOffsetInFuncletGCInfoHeader1573 bool IsOffsetInFunclet(UInt32 offset) 1574 { 1575 if (!hasFunclets) 1576 return false; 1577 1578 return (offset >= cbThisCodeBody); 1579 } 1580 #endif // BINDER 1581 IsValidEpilogOffsetGCInfoHeader1582 bool IsValidEpilogOffset(UInt32 epilogOffset, UInt32 epilogSize) 1583 { 1584 if (!this->HasVaryingEpilogSizes()) 1585 return (epilogOffset < this->GetFixedEpilogSize()); 1586 else 1587 return (epilogOffset < epilogSize); 1588 } 1589 1590 #ifdef RHDUMP GetBoolStrGCInfoHeader1591 char const * GetBoolStr(bool val) { return val ? " true" : "false"; } GetRetKindStrGCInfoHeader1592 char const * GetRetKindStr(int k) 1593 { 1594 switch (k) 1595 { 1596 case MRK_ReturnsScalar: return "scalar"; 1597 case MRK_ReturnsObject: return "object"; 1598 case MRK_ReturnsByref: return " byref"; 1599 case MRK_ReturnsToNative: return "native"; 1600 default: return "unknwn"; 1601 } 1602 } 1603 1604 #define PRINT_CALLEE_SAVE(name, mask, val) {if ((val) & (mask)) { printf(name); }} 1605 PrintCalleeSavedRegsGCInfoHeader1606 void PrintCalleeSavedRegs(UInt32 calleeSavedRegMask) 1607 { 1608 #ifdef _TARGET_ARM_ 1609 PRINT_CALLEE_SAVE(" r4" , CSR_MASK_R4 , calleeSavedRegMask); 1610 PRINT_CALLEE_SAVE(" r5" , CSR_MASK_R5 , calleeSavedRegMask); 1611 PRINT_CALLEE_SAVE(" r6" , CSR_MASK_R6 , calleeSavedRegMask); 1612 PRINT_CALLEE_SAVE(" r7" , CSR_MASK_R7 , calleeSavedRegMask); 1613 PRINT_CALLEE_SAVE(" r8" , CSR_MASK_R8 , calleeSavedRegMask); 1614 PRINT_CALLEE_SAVE(" r9" , CSR_MASK_R9 , calleeSavedRegMask); 1615 PRINT_CALLEE_SAVE(" r10", CSR_MASK_R10, calleeSavedRegMask); 1616 PRINT_CALLEE_SAVE(" r11", CSR_MASK_R11, calleeSavedRegMask); 1617 PRINT_CALLEE_SAVE(" lr" , CSR_MASK_LR , calleeSavedRegMask); 1618 #elif defined(_TARGET_ARM64_) 1619 PRINT_CALLEE_SAVE(" lr" , CSR_MASK_LR , calleeSavedRegMask); 1620 PRINT_CALLEE_SAVE(" x19", CSR_MASK_X19, calleeSavedRegMask); 1621 PRINT_CALLEE_SAVE(" x20", CSR_MASK_X20, calleeSavedRegMask); 1622 PRINT_CALLEE_SAVE(" x21", CSR_MASK_X21, calleeSavedRegMask); 1623 PRINT_CALLEE_SAVE(" x22", CSR_MASK_X22, calleeSavedRegMask); 1624 PRINT_CALLEE_SAVE(" x23", CSR_MASK_X23, calleeSavedRegMask); 1625 PRINT_CALLEE_SAVE(" x24", CSR_MASK_X24, calleeSavedRegMask); 1626 PRINT_CALLEE_SAVE(" x25", CSR_MASK_X25, calleeSavedRegMask); 1627 PRINT_CALLEE_SAVE(" x26", CSR_MASK_X26, calleeSavedRegMask); 1628 PRINT_CALLEE_SAVE(" x27", CSR_MASK_X27, calleeSavedRegMask); 1629 PRINT_CALLEE_SAVE(" x28", CSR_MASK_X28, calleeSavedRegMask); 1630 PRINT_CALLEE_SAVE(" fp" , CSR_MASK_FP , calleeSavedRegMask); 1631 #elif defined(_TARGET_X86_) 1632 PRINT_CALLEE_SAVE(" ebx", CSR_MASK_RBX, calleeSavedRegMask); 1633 PRINT_CALLEE_SAVE(" esi", CSR_MASK_RSI, calleeSavedRegMask); 1634 PRINT_CALLEE_SAVE(" edi", CSR_MASK_RDI, calleeSavedRegMask); 1635 PRINT_CALLEE_SAVE(" ebp", CSR_MASK_RBP, calleeSavedRegMask); 1636 #elif defined(_TARGET_AMD64_) 1637 PRINT_CALLEE_SAVE(" rbx", CSR_MASK_RBX, calleeSavedRegMask); 1638 PRINT_CALLEE_SAVE(" rsi", CSR_MASK_RSI, calleeSavedRegMask); 1639 PRINT_CALLEE_SAVE(" rdi", CSR_MASK_RDI, calleeSavedRegMask); 1640 PRINT_CALLEE_SAVE(" rbp", CSR_MASK_RBP, calleeSavedRegMask); 1641 PRINT_CALLEE_SAVE(" r12", CSR_MASK_R12, calleeSavedRegMask); 1642 PRINT_CALLEE_SAVE(" r13", CSR_MASK_R13, calleeSavedRegMask); 1643 PRINT_CALLEE_SAVE(" r14", CSR_MASK_R14, calleeSavedRegMask); 1644 PRINT_CALLEE_SAVE(" r15", CSR_MASK_R15, calleeSavedRegMask); 1645 #else 1646 #error unknown architecture 1647 #endif 1648 } 1649 PrintRegNumberGCInfoHeader1650 void PrintRegNumber(UInt8 regNumber) 1651 { 1652 switch (regNumber) 1653 { 1654 default: printf("???"); break; 1655 #ifdef _TARGET_ARM_ 1656 case RN_R0: printf(" r0"); break; 1657 case RN_R1: printf(" r1"); break; 1658 case RN_R2: printf(" r2"); break; 1659 case RN_R3: printf(" r3"); break; 1660 case RN_R4: printf(" r4"); break; 1661 case RN_R5: printf(" r5"); break; 1662 case RN_R6: printf(" r6"); break; 1663 case RN_R7: printf(" r7"); break; 1664 case RN_R8: printf(" r8"); break; 1665 case RN_R9: printf(" r9"); break; 1666 case RN_R10: printf("r10"); break; 1667 case RN_R11: printf("r11"); break; 1668 case RN_R12: printf("r12"); break; 1669 case RN_SP: printf(" sp"); break; 1670 case RN_LR: printf(" lr"); break; 1671 case RN_PC: printf(" pc"); break; 1672 #elif defined(_TARGET_ARM64_) 1673 case RN_X0: printf(" x0"); break; 1674 case RN_X1: printf(" x1"); break; 1675 case RN_X2: printf(" x2"); break; 1676 case RN_X3: printf(" x3"); break; 1677 case RN_X4: printf(" x4"); break; 1678 case RN_X5: printf(" x5"); break; 1679 case RN_X6: printf(" x6"); break; 1680 case RN_X7: printf(" x7"); break; 1681 case RN_X8: printf(" x8"); break; 1682 case RN_X9: printf(" x9"); break; 1683 case RN_X10: printf("x10"); break; 1684 case RN_X11: printf("x11"); break; 1685 case RN_X12: printf("x12"); break; 1686 case RN_X13: printf("x13"); break; 1687 case RN_X14: printf("x14"); break; 1688 case RN_X15: printf("x15"); break; 1689 1690 case RN_XIP0: printf("xip0"); break; 1691 case RN_XIP1: printf("xip1"); break; 1692 case RN_XPR: printf("xpr"); break; 1693 1694 case RN_X19: printf("x19"); break; 1695 case RN_X20: printf("x20"); break; 1696 case RN_X21: printf("x21"); break; 1697 case RN_X22: printf("x22"); break; 1698 case RN_X23: printf("x23"); break; 1699 case RN_X24: printf("x24"); break; 1700 case RN_X25: printf("x25"); break; 1701 case RN_X26: printf("x26"); break; 1702 case RN_X27: printf("x27"); break; 1703 case RN_X28: printf("x28"); break; 1704 1705 case RN_FP: printf(" fp"); break; 1706 case RN_LR: printf(" lr"); break; 1707 case RN_SP: printf(" sp"); break; 1708 #elif defined(_TARGET_X86_) 1709 case RN_EAX: printf("eax"); break; 1710 case RN_ECX: printf("ecx"); break; 1711 case RN_EDX: printf("edx"); break; 1712 case RN_EBX: printf("ebx"); break; 1713 case RN_ESP: printf("esp"); break; 1714 case RN_EBP: printf("ebp"); break; 1715 case RN_ESI: printf("esi"); break; 1716 case RN_EDI: printf("edi"); break; 1717 #elif defined(_TARGET_AMD64_) 1718 case RN_EAX: printf("rax"); break; 1719 case RN_ECX: printf("rcx"); break; 1720 case RN_EDX: printf("rdx"); break; 1721 case RN_EBX: printf("rbx"); break; 1722 case RN_ESP: printf("rsp"); break; 1723 case RN_EBP: printf("rbp"); break; 1724 case RN_ESI: printf("rsi"); break; 1725 case RN_EDI: printf("rdi"); break; 1726 case RN_R8: printf(" r8"); break; 1727 case RN_R9: printf(" r9"); break; 1728 case RN_R10: printf("r10"); break; 1729 case RN_R11: printf("r11"); break; 1730 case RN_R12: printf("r12"); break; 1731 case RN_R13: printf("r13"); break; 1732 case RN_R14: printf("r14"); break; 1733 case RN_R15: printf("r15"); break; 1734 #else 1735 #error unknown architecture 1736 #endif 1737 } 1738 } 1739 DumpGCInfoHeader1740 void Dump() 1741 { 1742 printf(" | prologSize: %02X"" | epilogSize: %02X"" | epilogCount: %02X"" | epilogAtEnd: %s\n", 1743 GetPrologSize(), PeekFixedEpilogSize(), epilogCount, GetBoolStr(epilogAtEnd)); 1744 printf(" | frameSize: %04X"" | ebpFrame: %s"" | hasFunclets: %s"" | returnKind: %s\n", 1745 GetFrameSize(), GetBoolStr(ebpFrame), GetBoolStr(hasFunclets), GetRetKindStr(returnKind)); 1746 printf(" | regMask: %04X" " {", calleeSavedRegMask); 1747 PrintCalleeSavedRegs(calleeSavedRegMask); 1748 printf(" }\n"); 1749 if (HasDynamicAlignment()) 1750 { 1751 printf(" | stackAlign: %02X"" | paramPtrReg: ", GetDynamicAlignment()); 1752 PrintRegNumber(paramPointerReg); 1753 printf("\n"); 1754 } 1755 if (hasGSCookie) 1756 { 1757 printf(" | gsCookieOffset: %04X\n", GetGSCookieOffset()); 1758 } 1759 #ifdef _TARGET_ARM_ 1760 if (arm_areParmOrVfpRegsPushed) 1761 { 1762 if (arm_parmRegsPushedSet != 0) 1763 { 1764 printf(" | parmRegs: %02X {", arm_parmRegsPushedSet); 1765 PRINT_CALLEE_SAVE(" r0", SR_MASK_R0, arm_parmRegsPushedSet); 1766 PRINT_CALLEE_SAVE(" r1", SR_MASK_R1, arm_parmRegsPushedSet); 1767 PRINT_CALLEE_SAVE(" r2", SR_MASK_R2, arm_parmRegsPushedSet); 1768 PRINT_CALLEE_SAVE(" r3", SR_MASK_R3, arm_parmRegsPushedSet); 1769 printf(" }\n"); 1770 } 1771 if (arm_vfpRegPushedCount != 0) 1772 { 1773 printf(" | vfpRegs: %d(%d) {", arm_vfpRegFirstPushed, arm_vfpRegPushedCount); 1774 printf(" d%d", arm_vfpRegFirstPushed); 1775 if (arm_vfpRegPushedCount > 1) 1776 printf("-d%d", arm_vfpRegFirstPushed + arm_vfpRegPushedCount - 1); 1777 printf(" }\n"); 1778 } 1779 } 1780 #elif defined(_TARGET_ARM64_) 1781 if (arm64_areParmOrVfpRegsPushed) 1782 { 1783 if (arm64_parmRegsPushedCount != 0) 1784 { 1785 printf(" | parmRegsCount: %d\n", arm64_parmRegsPushedCount); 1786 } 1787 if (arm64_vfpRegsPushedMask != 0) 1788 { 1789 printf(" | vfpRegs: %02X {", arm64_vfpRegsPushedMask); 1790 for (int reg = 0; reg < 8; reg++) 1791 { 1792 if (arm64_vfpRegsPushedMask & (1 << reg)) 1793 printf(" d%d", reg + 8); 1794 } 1795 printf(" }\n"); 1796 } 1797 } 1798 #elif defined(_TARGET_AMD64_) 1799 if (x64_hasSavedXmmRegs) 1800 { 1801 printf(" | xmmRegs: %04X {", x64_savedXmmRegMask); 1802 for (int reg = 6; reg < 16; reg++) 1803 { 1804 if (x64_savedXmmRegMask & (1<<reg)) 1805 printf(" xmm%d", reg); 1806 } 1807 printf(" }\n"); 1808 } 1809 #endif // _TARGET_ARM_ 1810 1811 // x64_framePtrOffsetSmall / [opt] x64_framePtrOffset 1812 // x86_argCountLow [opt] x86_argCountHigh 1813 // x86_argCountIsLarge 1814 // x86_hasStackChanges 1815 // [opt] reversePinvokeFrameOffset 1816 // [opt] numFunclets 1817 } 1818 #endif // RHDUMP 1819 }; 1820 1821 1822 1823 /*****************************************************************************/ 1824 #endif //_GCINFO_H_ 1825 /*****************************************************************************/ 1826