cpu_context.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Copyright 2014 The Crashpad Authors. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "snapshot/cpu_context.h"
  15. #include <stddef.h>
  16. #include <string.h>
  17. #include <iterator>
  18. #include "base/notreached.h"
  19. #include "util/misc/arraysize.h"
  20. #include "util/misc/implicit_cast.h"
  21. namespace crashpad {
  22. namespace {
  23. // Sanity-check complex structures to ensure interoperability.
  24. static_assert(sizeof(CPUContextX86::Fsave) == 108, "CPUContextX86::Fsave size");
  25. static_assert(sizeof(CPUContextX86::Fxsave) == 512,
  26. "CPUContextX86::Fxsave size");
  27. static_assert(sizeof(CPUContextX86_64::Fxsave) == 512,
  28. "CPUContextX86_64::Fxsave size");
  29. enum {
  30. kX87TagValid = 0,
  31. kX87TagZero,
  32. kX87TagSpecial,
  33. kX87TagEmpty,
  34. };
  35. } // namespace
  36. // static
  37. void CPUContextX86::FxsaveToFsave(const Fxsave& fxsave, Fsave* fsave) {
  38. fsave->fcw = fxsave.fcw;
  39. fsave->reserved_1 = 0;
  40. fsave->fsw = fxsave.fsw;
  41. fsave->reserved_2 = 0;
  42. fsave->ftw = FxsaveToFsaveTagWord(fxsave.fsw, fxsave.ftw, fxsave.st_mm);
  43. fsave->reserved_3 = 0;
  44. fsave->fpu_ip = fxsave.fpu_ip;
  45. fsave->fpu_cs = fxsave.fpu_cs;
  46. fsave->fop = fxsave.fop;
  47. fsave->fpu_dp = fxsave.fpu_dp;
  48. fsave->fpu_ds = fxsave.fpu_ds;
  49. fsave->reserved_4 = 0;
  50. static_assert(ArraySize(fsave->st) == ArraySize(fxsave.st_mm),
  51. "FPU stack registers must be equivalent");
  52. for (size_t index = 0; index < std::size(fsave->st); ++index) {
  53. memcpy(fsave->st[index], fxsave.st_mm[index].st, sizeof(fsave->st[index]));
  54. }
  55. }
  56. // static
  57. void CPUContextX86::FsaveToFxsave(const Fsave& fsave, Fxsave* fxsave) {
  58. fxsave->fcw = fsave.fcw;
  59. fxsave->fsw = fsave.fsw;
  60. fxsave->ftw = FsaveToFxsaveTagWord(fsave.ftw);
  61. fxsave->reserved_1 = 0;
  62. fxsave->fop = fsave.fop;
  63. fxsave->fpu_ip = fsave.fpu_ip;
  64. fxsave->fpu_cs = fsave.fpu_cs;
  65. fxsave->reserved_2 = 0;
  66. fxsave->fpu_dp = fsave.fpu_dp;
  67. fxsave->fpu_ds = fsave.fpu_ds;
  68. fxsave->reserved_3 = 0;
  69. fxsave->mxcsr = 0;
  70. fxsave->mxcsr_mask = 0;
  71. static_assert(ArraySize(fxsave->st_mm) == ArraySize(fsave.st),
  72. "FPU stack registers must be equivalent");
  73. for (size_t index = 0; index < std::size(fsave.st); ++index) {
  74. memcpy(fxsave->st_mm[index].st, fsave.st[index], sizeof(fsave.st[index]));
  75. memset(fxsave->st_mm[index].st_reserved,
  76. 0,
  77. sizeof(fxsave->st_mm[index].st_reserved));
  78. }
  79. memset(fxsave->xmm, 0, sizeof(*fxsave) - offsetof(Fxsave, xmm));
  80. }
  81. // static
  82. uint16_t CPUContextX86::FxsaveToFsaveTagWord(
  83. uint16_t fsw,
  84. uint8_t fxsave_tag,
  85. const CPUContextX86::X87OrMMXRegister st_mm[8]) {
  86. // The x87 tag word (in both abridged and full form) identifies physical
  87. // registers, but |st_mm| is arranged in logical stack order. In order to map
  88. // physical tag word bits to the logical stack registers they correspond to,
  89. // the “stack top” value from the x87 status word is necessary.
  90. int stack_top = (fsw >> 11) & 0x7;
  91. uint16_t fsave_tag = 0;
  92. for (int physical_index = 0; physical_index < 8; ++physical_index) {
  93. bool fxsave_bit = (fxsave_tag & (1 << physical_index)) != 0;
  94. uint8_t fsave_bits;
  95. if (fxsave_bit) {
  96. int st_index = (physical_index + 8 - stack_top) % 8;
  97. const CPUContextX86::X87Register& st = st_mm[st_index].st;
  98. uint32_t exponent = ((st[9] & 0x7f) << 8) | st[8];
  99. if (exponent == 0x7fff) {
  100. // Infinity, NaN, pseudo-infinity, or pseudo-NaN. If it was important to
  101. // distinguish between these, the J bit and the M bit (the most
  102. // significant bit of |fraction|) could be consulted.
  103. fsave_bits = kX87TagSpecial;
  104. } else {
  105. // The integer bit the “J bit”.
  106. bool integer_bit = (st[7] & 0x80) != 0;
  107. if (exponent == 0) {
  108. uint64_t fraction = ((implicit_cast<uint64_t>(st[7]) & 0x7f) << 56) |
  109. (implicit_cast<uint64_t>(st[6]) << 48) |
  110. (implicit_cast<uint64_t>(st[5]) << 40) |
  111. (implicit_cast<uint64_t>(st[4]) << 32) |
  112. (implicit_cast<uint32_t>(st[3]) << 24) |
  113. (st[2] << 16) | (st[1] << 8) | st[0];
  114. if (!integer_bit && fraction == 0) {
  115. fsave_bits = kX87TagZero;
  116. } else {
  117. // Denormal (if the J bit is clear) or pseudo-denormal.
  118. fsave_bits = kX87TagSpecial;
  119. }
  120. } else if (integer_bit) {
  121. fsave_bits = kX87TagValid;
  122. } else {
  123. // Unnormal.
  124. fsave_bits = kX87TagSpecial;
  125. }
  126. }
  127. } else {
  128. fsave_bits = kX87TagEmpty;
  129. }
  130. fsave_tag |= (fsave_bits << (physical_index * 2));
  131. }
  132. return fsave_tag;
  133. }
  134. // static
  135. uint8_t CPUContextX86::FsaveToFxsaveTagWord(uint16_t fsave_tag) {
  136. uint8_t fxsave_tag = 0;
  137. for (int physical_index = 0; physical_index < 8; ++physical_index) {
  138. const uint8_t fsave_bits = (fsave_tag >> (physical_index * 2)) & 0x3;
  139. const bool fxsave_bit = fsave_bits != kX87TagEmpty;
  140. fxsave_tag |= fxsave_bit << physical_index;
  141. }
  142. return fxsave_tag;
  143. }
  144. uint64_t CPUContext::InstructionPointer() const {
  145. switch (architecture) {
  146. case kCPUArchitectureX86:
  147. return x86->eip;
  148. case kCPUArchitectureX86_64:
  149. return x86_64->rip;
  150. case kCPUArchitectureARM:
  151. return arm->pc;
  152. case kCPUArchitectureARM64:
  153. return arm64->pc;
  154. default:
  155. NOTREACHED();
  156. return ~0ull;
  157. }
  158. }
  159. uint64_t CPUContext::StackPointer() const {
  160. switch (architecture) {
  161. case kCPUArchitectureX86:
  162. return x86->esp;
  163. case kCPUArchitectureX86_64:
  164. return x86_64->rsp;
  165. case kCPUArchitectureARM:
  166. return arm->sp;
  167. case kCPUArchitectureARM64:
  168. return arm64->sp;
  169. default:
  170. NOTREACHED();
  171. return ~0ull;
  172. }
  173. }
  174. uint64_t CPUContext::ShadowStackPointer() const {
  175. switch (architecture) {
  176. case kCPUArchitectureX86:
  177. case kCPUArchitectureARM:
  178. case kCPUArchitectureARM64:
  179. NOTREACHED();
  180. return 0;
  181. case kCPUArchitectureX86_64:
  182. return x86_64->xstate.cet_u.ssp;
  183. default:
  184. NOTREACHED();
  185. return ~0ull;
  186. }
  187. }
  188. bool CPUContext::HasShadowStack() const {
  189. switch (architecture) {
  190. case kCPUArchitectureX86:
  191. case kCPUArchitectureARM:
  192. case kCPUArchitectureARM64:
  193. return false;
  194. case kCPUArchitectureX86_64:
  195. return x86_64->xstate.cet_u.cetmsr != 0;
  196. default:
  197. NOTREACHED();
  198. return false;
  199. }
  200. }
  201. bool CPUContext::Is64Bit() const {
  202. switch (architecture) {
  203. case kCPUArchitectureX86_64:
  204. case kCPUArchitectureARM64:
  205. case kCPUArchitectureMIPS64EL:
  206. case kCPUArchitectureRISCV64:
  207. return true;
  208. case kCPUArchitectureX86:
  209. case kCPUArchitectureARM:
  210. case kCPUArchitectureMIPSEL:
  211. case kCPUArchitectureRISCV:
  212. return false;
  213. default:
  214. NOTREACHED();
  215. return false;
  216. }
  217. }
  218. } // namespace crashpad