| OLD | NEW |
| (Empty) | |
| 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 |
| 15 #include "minidump/test/minidump_context_test_util.h" |
| 16 |
| 17 #include "base/basictypes.h" |
| 18 #include "base/format_macros.h" |
| 19 #include "base/strings/stringprintf.h" |
| 20 #include "gtest/gtest.h" |
| 21 #include "snapshot/cpu_context.h" |
| 22 #include "snapshot/test/test_cpu_context.h" |
| 23 |
| 24 namespace crashpad { |
| 25 namespace test { |
| 26 |
| 27 void InitializeMinidumpContextX86(MinidumpContextX86* context, uint32_t seed) { |
| 28 if (seed == 0) { |
| 29 memset(context, 0, sizeof(*context)); |
| 30 context->context_flags = kMinidumpContextX86; |
| 31 return; |
| 32 } |
| 33 |
| 34 context->context_flags = kMinidumpContextX86All; |
| 35 |
| 36 uint32_t value = seed; |
| 37 |
| 38 context->eax = value++; |
| 39 context->ebx = value++; |
| 40 context->ecx = value++; |
| 41 context->edx = value++; |
| 42 context->edi = value++; |
| 43 context->esi = value++; |
| 44 context->ebp = value++; |
| 45 context->esp = value++; |
| 46 context->eip = value++; |
| 47 context->eflags = value++; |
| 48 context->cs = value++ & 0xffff; |
| 49 context->ds = value++ & 0xffff; |
| 50 context->es = value++ & 0xffff; |
| 51 context->fs = value++ & 0xffff; |
| 52 context->gs = value++ & 0xffff; |
| 53 context->ss = value++ & 0xffff; |
| 54 |
| 55 InitializeCPUContextX86Fxsave(&context->fxsave, &value); |
| 56 |
| 57 context->dr0 = value++; |
| 58 context->dr1 = value++; |
| 59 context->dr2 = value++; |
| 60 context->dr3 = value++; |
| 61 value += 2; // Minidumps don’t carry dr4 or dr5. |
| 62 context->dr6 = value++; |
| 63 context->dr7 = value++; |
| 64 |
| 65 // Copy the values that are aliased between the fxsave area |
| 66 // (context->extended_registers) and the floating-point save area |
| 67 // (context->float_save). |
| 68 context->float_save.control_word = context->fxsave.fcw; |
| 69 context->float_save.status_word = context->fxsave.fsw; |
| 70 context->float_save.tag_word = CPUContextX86::FxsaveToFsaveTagWord( |
| 71 context->fxsave.fsw, context->fxsave.ftw, context->fxsave.st_mm); |
| 72 context->float_save.error_offset = context->fxsave.fpu_ip; |
| 73 context->float_save.error_selector = context->fxsave.fpu_cs; |
| 74 context->float_save.data_offset = context->fxsave.fpu_dp; |
| 75 context->float_save.data_selector = context->fxsave.fpu_ds; |
| 76 for (size_t st_mm_index = 0; |
| 77 st_mm_index < arraysize(context->fxsave.st_mm); |
| 78 ++st_mm_index) { |
| 79 for (size_t byte = 0; |
| 80 byte < arraysize(context->fxsave.st_mm[st_mm_index].st); |
| 81 ++byte) { |
| 82 size_t st_index = |
| 83 st_mm_index * arraysize(context->fxsave.st_mm[st_mm_index].st) + byte; |
| 84 context->float_save.register_area[st_index] = |
| 85 context->fxsave.st_mm[st_mm_index].st[byte]; |
| 86 } |
| 87 } |
| 88 |
| 89 // Set this field last, because it has no analogue in CPUContextX86. |
| 90 context->float_save.spare_0 = value++; |
| 91 } |
| 92 |
| 93 void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context, |
| 94 uint32_t seed) { |
| 95 if (seed == 0) { |
| 96 memset(context, 0, sizeof(*context)); |
| 97 context->context_flags = kMinidumpContextAMD64; |
| 98 return; |
| 99 } |
| 100 |
| 101 context->context_flags = kMinidumpContextAMD64All; |
| 102 |
| 103 uint32_t value = seed; |
| 104 |
| 105 context->rax = value++; |
| 106 context->rbx = value++; |
| 107 context->rcx = value++; |
| 108 context->rdx = value++; |
| 109 context->rdi = value++; |
| 110 context->rsi = value++; |
| 111 context->rbp = value++; |
| 112 context->rsp = value++; |
| 113 context->r8 = value++; |
| 114 context->r9 = value++; |
| 115 context->r10 = value++; |
| 116 context->r11 = value++; |
| 117 context->r12 = value++; |
| 118 context->r13 = value++; |
| 119 context->r14 = value++; |
| 120 context->r15 = value++; |
| 121 context->rip = value++; |
| 122 context->eflags = value++; |
| 123 context->cs = static_cast<uint16_t>(value++); |
| 124 context->fs = static_cast<uint16_t>(value++); |
| 125 context->gs = static_cast<uint16_t>(value++); |
| 126 |
| 127 InitializeCPUContextX86_64Fxsave(&context->fxsave, &value); |
| 128 |
| 129 // mxcsr appears twice, and the two values should be aliased. |
| 130 context->mx_csr = context->fxsave.mxcsr; |
| 131 |
| 132 context->dr0 = value++; |
| 133 context->dr1 = value++; |
| 134 context->dr2 = value++; |
| 135 context->dr3 = value++; |
| 136 value += 2; // Minidumps don’t carry dr4 or dr5. |
| 137 context->dr6 = value++; |
| 138 context->dr7 = value++; |
| 139 |
| 140 // Set these fields last, because they have no analogues in CPUContextX86_64. |
| 141 context->p1_home = value++; |
| 142 context->p2_home = value++; |
| 143 context->p3_home = value++; |
| 144 context->p4_home = value++; |
| 145 context->p5_home = value++; |
| 146 context->p6_home = value++; |
| 147 context->ds = static_cast<uint16_t>(value++); |
| 148 context->es = static_cast<uint16_t>(value++); |
| 149 context->ss = static_cast<uint16_t>(value++); |
| 150 for (size_t index = 0; index < arraysize(context->vector_register); ++index) { |
| 151 context->vector_register[index].lo = value++; |
| 152 context->vector_register[index].hi = value++; |
| 153 } |
| 154 context->vector_control = value++; |
| 155 context->debug_control = value++; |
| 156 context->last_branch_to_rip = value++; |
| 157 context->last_branch_from_rip = value++; |
| 158 context->last_exception_to_rip = value++; |
| 159 context->last_exception_from_rip = value++; |
| 160 } |
| 161 |
| 162 namespace { |
| 163 |
| 164 // Using gtest assertions, compares |expected| to |observed|. This is |
| 165 // templatized because the CPUContextX86::Fxsave and CPUContextX86_64::Fxsave |
| 166 // are nearly identical but have different sizes for the members |xmm|, |
| 167 // |reserved_4|, and |available|. |
| 168 template <typename FxsaveType> |
| 169 void ExpectMinidumpContextFxsave(const FxsaveType* expected, |
| 170 const FxsaveType* observed) { |
| 171 EXPECT_EQ(expected->fcw, observed->fcw); |
| 172 EXPECT_EQ(expected->fsw, observed->fsw); |
| 173 EXPECT_EQ(expected->ftw, observed->ftw); |
| 174 EXPECT_EQ(expected->reserved_1, observed->reserved_1); |
| 175 EXPECT_EQ(expected->fop, observed->fop); |
| 176 EXPECT_EQ(expected->fpu_ip, observed->fpu_ip); |
| 177 EXPECT_EQ(expected->fpu_cs, observed->fpu_cs); |
| 178 EXPECT_EQ(expected->reserved_2, observed->reserved_2); |
| 179 EXPECT_EQ(expected->fpu_dp, observed->fpu_dp); |
| 180 EXPECT_EQ(expected->fpu_ds, observed->fpu_ds); |
| 181 EXPECT_EQ(expected->reserved_3, observed->reserved_3); |
| 182 EXPECT_EQ(expected->mxcsr, observed->mxcsr); |
| 183 EXPECT_EQ(expected->mxcsr_mask, observed->mxcsr_mask); |
| 184 for (size_t st_mm_index = 0; |
| 185 st_mm_index < arraysize(expected->st_mm); |
| 186 ++st_mm_index) { |
| 187 SCOPED_TRACE(base::StringPrintf("st_mm_index %" PRIuS, st_mm_index)); |
| 188 for (size_t byte = 0; |
| 189 byte < arraysize(expected->st_mm[st_mm_index].st); |
| 190 ++byte) { |
| 191 EXPECT_EQ(expected->st_mm[st_mm_index].st[byte], |
| 192 observed->st_mm[st_mm_index].st[byte]) << "byte " << byte; |
| 193 } |
| 194 for (size_t byte = 0; |
| 195 byte < arraysize(expected->st_mm[st_mm_index].st_reserved); |
| 196 ++byte) { |
| 197 EXPECT_EQ(expected->st_mm[st_mm_index].st_reserved[byte], |
| 198 observed->st_mm[st_mm_index].st_reserved[byte]) |
| 199 << "byte " << byte; |
| 200 } |
| 201 } |
| 202 for (size_t xmm_index = 0; |
| 203 xmm_index < arraysize(expected->xmm); |
| 204 ++xmm_index) { |
| 205 SCOPED_TRACE(base::StringPrintf("xmm_index %" PRIuS, xmm_index)); |
| 206 for (size_t byte = 0; byte < arraysize(expected->xmm[xmm_index]); ++byte) { |
| 207 EXPECT_EQ(expected->xmm[xmm_index][byte], observed->xmm[xmm_index][byte]) |
| 208 << "byte " << byte; |
| 209 } |
| 210 } |
| 211 for (size_t byte = 0; byte < arraysize(expected->reserved_4); ++byte) { |
| 212 EXPECT_EQ(expected->reserved_4[byte], observed->reserved_4[byte]) |
| 213 << "byte " << byte; |
| 214 } |
| 215 for (size_t byte = 0; byte < arraysize(expected->available); ++byte) { |
| 216 EXPECT_EQ(expected->available[byte], observed->available[byte]) |
| 217 << "byte " << byte; |
| 218 } |
| 219 } |
| 220 |
| 221 } // namespace |
| 222 |
| 223 void ExpectMinidumpContextX86( |
| 224 uint32_t expect_seed, const MinidumpContextX86* observed, bool snapshot) { |
| 225 MinidumpContextX86 expected; |
| 226 InitializeMinidumpContextX86(&expected, expect_seed); |
| 227 |
| 228 EXPECT_EQ(expected.context_flags, observed->context_flags); |
| 229 EXPECT_EQ(expected.dr0, observed->dr0); |
| 230 EXPECT_EQ(expected.dr1, observed->dr1); |
| 231 EXPECT_EQ(expected.dr2, observed->dr2); |
| 232 EXPECT_EQ(expected.dr3, observed->dr3); |
| 233 EXPECT_EQ(expected.dr6, observed->dr6); |
| 234 EXPECT_EQ(expected.dr7, observed->dr7); |
| 235 |
| 236 EXPECT_EQ(expected.float_save.control_word, |
| 237 observed->float_save.control_word); |
| 238 EXPECT_EQ(expected.float_save.status_word, observed->float_save.status_word); |
| 239 EXPECT_EQ(expected.float_save.tag_word, observed->float_save.tag_word); |
| 240 EXPECT_EQ(expected.float_save.error_offset, |
| 241 observed->float_save.error_offset); |
| 242 EXPECT_EQ(expected.float_save.error_selector, |
| 243 observed->float_save.error_selector); |
| 244 EXPECT_EQ(expected.float_save.data_offset, observed->float_save.data_offset); |
| 245 EXPECT_EQ(expected.float_save.data_selector, |
| 246 observed->float_save.data_selector); |
| 247 for (size_t index = 0; |
| 248 index < arraysize(expected.float_save.register_area); |
| 249 ++index) { |
| 250 EXPECT_EQ(expected.float_save.register_area[index], |
| 251 observed->float_save.register_area[index]) << "index " << index; |
| 252 } |
| 253 if (snapshot) { |
| 254 EXPECT_EQ(0u, observed->float_save.spare_0); |
| 255 } else { |
| 256 EXPECT_EQ(expected.float_save.spare_0, observed->float_save.spare_0); |
| 257 } |
| 258 |
| 259 EXPECT_EQ(expected.gs, observed->gs); |
| 260 EXPECT_EQ(expected.fs, observed->fs); |
| 261 EXPECT_EQ(expected.es, observed->es); |
| 262 EXPECT_EQ(expected.ds, observed->ds); |
| 263 EXPECT_EQ(expected.edi, observed->edi); |
| 264 EXPECT_EQ(expected.esi, observed->esi); |
| 265 EXPECT_EQ(expected.ebx, observed->ebx); |
| 266 EXPECT_EQ(expected.edx, observed->edx); |
| 267 EXPECT_EQ(expected.ecx, observed->ecx); |
| 268 EXPECT_EQ(expected.eax, observed->eax); |
| 269 EXPECT_EQ(expected.ebp, observed->ebp); |
| 270 EXPECT_EQ(expected.eip, observed->eip); |
| 271 EXPECT_EQ(expected.cs, observed->cs); |
| 272 EXPECT_EQ(expected.eflags, observed->eflags); |
| 273 EXPECT_EQ(expected.esp, observed->esp); |
| 274 EXPECT_EQ(expected.ss, observed->ss); |
| 275 |
| 276 ExpectMinidumpContextFxsave(&expected.fxsave, &observed->fxsave); |
| 277 } |
| 278 |
| 279 void ExpectMinidumpContextAMD64( |
| 280 uint32_t expect_seed, const MinidumpContextAMD64* observed, bool snapshot) { |
| 281 MinidumpContextAMD64 expected; |
| 282 InitializeMinidumpContextAMD64(&expected, expect_seed); |
| 283 |
| 284 EXPECT_EQ(expected.context_flags, observed->context_flags); |
| 285 |
| 286 if (snapshot) { |
| 287 EXPECT_EQ(0u, observed->p1_home); |
| 288 EXPECT_EQ(0u, observed->p2_home); |
| 289 EXPECT_EQ(0u, observed->p3_home); |
| 290 EXPECT_EQ(0u, observed->p4_home); |
| 291 EXPECT_EQ(0u, observed->p5_home); |
| 292 EXPECT_EQ(0u, observed->p6_home); |
| 293 } else { |
| 294 EXPECT_EQ(expected.p1_home, observed->p1_home); |
| 295 EXPECT_EQ(expected.p2_home, observed->p2_home); |
| 296 EXPECT_EQ(expected.p3_home, observed->p3_home); |
| 297 EXPECT_EQ(expected.p4_home, observed->p4_home); |
| 298 EXPECT_EQ(expected.p5_home, observed->p5_home); |
| 299 EXPECT_EQ(expected.p6_home, observed->p6_home); |
| 300 } |
| 301 |
| 302 EXPECT_EQ(expected.mx_csr, observed->mx_csr); |
| 303 |
| 304 EXPECT_EQ(expected.cs, observed->cs); |
| 305 if (snapshot) { |
| 306 EXPECT_EQ(0u, observed->ds); |
| 307 EXPECT_EQ(0u, observed->es); |
| 308 } else { |
| 309 EXPECT_EQ(expected.ds, observed->ds); |
| 310 EXPECT_EQ(expected.es, observed->es); |
| 311 } |
| 312 EXPECT_EQ(expected.fs, observed->fs); |
| 313 EXPECT_EQ(expected.gs, observed->gs); |
| 314 if (snapshot) { |
| 315 EXPECT_EQ(0u, observed->ss); |
| 316 } else { |
| 317 EXPECT_EQ(expected.ss, observed->ss); |
| 318 } |
| 319 |
| 320 EXPECT_EQ(expected.eflags, observed->eflags); |
| 321 |
| 322 EXPECT_EQ(expected.dr0, observed->dr0); |
| 323 EXPECT_EQ(expected.dr1, observed->dr1); |
| 324 EXPECT_EQ(expected.dr2, observed->dr2); |
| 325 EXPECT_EQ(expected.dr3, observed->dr3); |
| 326 EXPECT_EQ(expected.dr6, observed->dr6); |
| 327 EXPECT_EQ(expected.dr7, observed->dr7); |
| 328 |
| 329 EXPECT_EQ(expected.rax, observed->rax); |
| 330 EXPECT_EQ(expected.rcx, observed->rcx); |
| 331 EXPECT_EQ(expected.rdx, observed->rdx); |
| 332 EXPECT_EQ(expected.rbx, observed->rbx); |
| 333 EXPECT_EQ(expected.rsp, observed->rsp); |
| 334 EXPECT_EQ(expected.rbp, observed->rbp); |
| 335 EXPECT_EQ(expected.rsi, observed->rsi); |
| 336 EXPECT_EQ(expected.rdi, observed->rdi); |
| 337 EXPECT_EQ(expected.r8, observed->r8); |
| 338 EXPECT_EQ(expected.r9, observed->r9); |
| 339 EXPECT_EQ(expected.r10, observed->r10); |
| 340 EXPECT_EQ(expected.r11, observed->r11); |
| 341 EXPECT_EQ(expected.r12, observed->r12); |
| 342 EXPECT_EQ(expected.r13, observed->r13); |
| 343 EXPECT_EQ(expected.r14, observed->r14); |
| 344 EXPECT_EQ(expected.r15, observed->r15); |
| 345 EXPECT_EQ(expected.rip, observed->rip); |
| 346 |
| 347 ExpectMinidumpContextFxsave(&expected.fxsave, &observed->fxsave); |
| 348 |
| 349 for (size_t index = 0; index < arraysize(expected.vector_register); ++index) { |
| 350 if (snapshot) { |
| 351 EXPECT_EQ(0u, observed->vector_register[index].lo) << "index " << index; |
| 352 EXPECT_EQ(0u, observed->vector_register[index].hi) << "index " << index; |
| 353 } else { |
| 354 EXPECT_EQ(expected.vector_register[index].lo, |
| 355 observed->vector_register[index].lo) << "index " << index; |
| 356 EXPECT_EQ(expected.vector_register[index].hi, |
| 357 observed->vector_register[index].hi) << "index " << index; |
| 358 } |
| 359 } |
| 360 |
| 361 if (snapshot) { |
| 362 EXPECT_EQ(0u, observed->vector_control); |
| 363 EXPECT_EQ(0u, observed->debug_control); |
| 364 EXPECT_EQ(0u, observed->last_branch_to_rip); |
| 365 EXPECT_EQ(0u, observed->last_branch_from_rip); |
| 366 EXPECT_EQ(0u, observed->last_exception_to_rip); |
| 367 EXPECT_EQ(0u, observed->last_exception_from_rip); |
| 368 } else { |
| 369 EXPECT_EQ(expected.vector_control, observed->vector_control); |
| 370 EXPECT_EQ(expected.debug_control, observed->debug_control); |
| 371 EXPECT_EQ(expected.last_branch_to_rip, observed->last_branch_to_rip); |
| 372 EXPECT_EQ(expected.last_branch_from_rip, observed->last_branch_from_rip); |
| 373 EXPECT_EQ(expected.last_exception_to_rip, observed->last_exception_to_rip); |
| 374 EXPECT_EQ(expected.last_exception_from_rip, |
| 375 observed->last_exception_from_rip); |
| 376 } |
| 377 } |
| 378 |
| 379 } // namespace test |
| 380 } // namespace crashpad |
| OLD | NEW |