Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/mdb/intel/mdb/proc_x86util.c
+++ new/usr/src/cmd/mdb/intel/mdb/proc_x86util.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /*
27 27 * Copyright 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com>
28 28 * Copyright 2023 Oxide Computer Company
29 29 */
30 30
31 31 /*
32 32 * Consolidated routines that are shared between the 32-bit and 64-bit x86 mdb
33 33 * proc targets.
34 34 */
35 35
36 36 #include <mdb/mdb_proc.h>
37 37 #include <mdb/mdb_err.h>
38 38 #include <mdb/proc_x86util.h>
39 39 #include <mdb/mdb.h>
40 40
41 41 #include <libproc.h>
42 42 #include <sys/fp.h>
43 43 #include <ieeefp.h>
44 44 #include <sys/sysmacros.h>
45 45
46 46 const char *
47 47 fpcw2str(uint32_t cw, char *buf, size_t nbytes)
48 48 {
49 49 char *end = buf + nbytes;
50 50 char *p = buf;
51 51
52 52 buf[0] = '\0';
53 53
54 54 /*
55 55 * Decode all exception masks in the x87 FPU Control Word.
56 56 *
57 57 * See here:
58 58 * Intel® 64 and IA-32 Architectures Software Developer’s Manual,
59 59 * Volume 1: Basic Architecture, 8.1.5 x87 FPU Control Word
60 60 */
61 61 if (cw & FPIM) /* Invalid operation mask. */
62 62 p += mdb_snprintf(p, (size_t)(end - p), "|IM");
63 63 if (cw & FPDM) /* Denormalized operand mask. */
64 64 p += mdb_snprintf(p, (size_t)(end - p), "|DM");
65 65 if (cw & FPZM) /* Zero divide mask. */
66 66 p += mdb_snprintf(p, (size_t)(end - p), "|ZM");
67 67 if (cw & FPOM) /* Overflow mask. */
68 68 p += mdb_snprintf(p, (size_t)(end - p), "|OM");
69 69 if (cw & FPUM) /* Underflow mask. */
70 70 p += mdb_snprintf(p, (size_t)(end - p), "|UM");
71 71 if (cw & FPPM) /* Precision mask. */
72 72 p += mdb_snprintf(p, (size_t)(end - p), "|PM");
73 73
74 74 /*
75 75 * Decode precision control options.
76 76 */
77 77 switch (cw & FPPC) {
78 78 case FPSIG24:
79 79 /* 24-bit significand, single precision. */
80 80 p += mdb_snprintf(p, (size_t)(end - p), "|SIG24");
81 81 break;
82 82 case FPSIG53:
83 83 /* 53-bit significand, double precision. */
84 84 p += mdb_snprintf(p, (size_t)(end - p), "|SIG53");
85 85 break;
86 86 case FPSIG64:
87 87 /* 64-bit significand, double extended precision. */
88 88 p += mdb_snprintf(p, (size_t)(end - p), "|SIG64");
89 89 break;
90 90 default:
91 91 /*
92 92 * Should never happen.
93 93 * Value 0x00000100 is 'Reserved'.
94 94 */
95 95 break;
96 96 }
97 97
98 98 /*
99 99 * Decode rounding control options.
100 100 */
101 101 switch (cw & FPRC) {
102 102 case FPRTN:
103 103 /* Round to nearest, or to even if equidistant. */
104 104 p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
105 105 break;
106 106 case FPRD:
107 107 /* Round down. */
108 108 p += mdb_snprintf(p, (size_t)(end - p), "|RD");
109 109 break;
110 110 case FPRU:
111 111 /* Round up. */
112 112 p += mdb_snprintf(p, (size_t)(end - p), "|RU");
113 113 break;
114 114 case FPCHOP:
115 115 /* Truncate. */
116 116 p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
117 117 break;
118 118 default:
119 119 /*
120 120 * This is a two-bit field.
121 121 * No other options left.
122 122 */
123 123 break;
124 124 }
125 125
126 126 /*
127 127 * Decode infinity control options.
128 128 *
129 129 * This field has been retained for compatibility with
130 130 * the 287 and earlier co-processors.
131 131 * In the more modern FPUs, this bit is disregarded and
132 132 * both -infinity and +infinity are respected.
133 133 * Comment source: SIMPLY FPU by Raymond Filiatreault
134 134 */
135 135 switch (cw & FPIC) {
136 136 case FPP:
137 137 /*
138 138 * Projective infinity.
139 139 * Both -infinity and +infinity are treated as
140 140 * unsigned infinity.
141 141 */
142 142 p += mdb_snprintf(p, (size_t)(end - p), "|P");
143 143 break;
144 144 case FPA:
145 145 /*
146 146 * Affine infinity.
147 147 * Respects both -infinity and +infinity.
148 148 */
149 149 p += mdb_snprintf(p, (size_t)(end - p), "|A");
150 150 break;
151 151 default:
152 152 /*
153 153 * This is a one-bit field.
154 154 * No other options left.
155 155 */
156 156 break;
157 157 }
158 158
159 159 if (cw & WFPB17)
160 160 p += mdb_snprintf(p, (size_t)(end - p), "|WFPB17");
161 161 if (cw & WFPB24)
162 162 p += mdb_snprintf(p, (size_t)(end - p), "|WFPB24");
163 163
164 164 if (buf[0] == '|')
165 165 return (buf + 1);
166 166
167 167 return ("0");
168 168 }
169 169
170 170 const char *
171 171 fpsw2str(uint32_t cw, char *buf, size_t nbytes)
172 172 {
173 173 char *end = buf + nbytes;
174 174 char *p = buf;
175 175
176 176 buf[0] = '\0';
177 177
178 178 /*
179 179 * Decode all masks in the 80387 status word.
180 180 */
181 181 if (cw & FPS_IE)
182 182 p += mdb_snprintf(p, (size_t)(end - p), "|IE");
183 183 if (cw & FPS_DE)
184 184 p += mdb_snprintf(p, (size_t)(end - p), "|DE");
185 185 if (cw & FPS_ZE)
186 186 p += mdb_snprintf(p, (size_t)(end - p), "|ZE");
187 187 if (cw & FPS_OE)
188 188 p += mdb_snprintf(p, (size_t)(end - p), "|OE");
189 189 if (cw & FPS_UE)
190 190 p += mdb_snprintf(p, (size_t)(end - p), "|UE");
191 191 if (cw & FPS_PE)
192 192 p += mdb_snprintf(p, (size_t)(end - p), "|PE");
193 193 if (cw & FPS_SF)
194 194 p += mdb_snprintf(p, (size_t)(end - p), "|SF");
195 195 if (cw & FPS_ES)
196 196 p += mdb_snprintf(p, (size_t)(end - p), "|ES");
197 197 if (cw & FPS_C0)
198 198 p += mdb_snprintf(p, (size_t)(end - p), "|C0");
199 199 if (cw & FPS_C1)
200 200 p += mdb_snprintf(p, (size_t)(end - p), "|C1");
201 201 if (cw & FPS_C2)
202 202 p += mdb_snprintf(p, (size_t)(end - p), "|C2");
203 203 if (cw & FPS_C3)
204 204 p += mdb_snprintf(p, (size_t)(end - p), "|C3");
205 205 if (cw & FPS_B)
206 206 p += mdb_snprintf(p, (size_t)(end - p), "|B");
207 207
208 208 if (buf[0] == '|')
209 209 return (buf + 1);
210 210
211 211 return ("0");
212 212 }
213 213
214 214 const char *
215 215 fpmxcsr2str(uint32_t mxcsr, char *buf, size_t nbytes)
216 216 {
217 217 char *end = buf + nbytes;
218 218 char *p = buf;
219 219
220 220 buf[0] = '\0';
221 221
222 222 /*
223 223 * Decode the MXCSR word
224 224 */
225 225 if (mxcsr & SSE_IE)
226 226 p += mdb_snprintf(p, (size_t)(end - p), "|IE");
227 227 if (mxcsr & SSE_DE)
228 228 p += mdb_snprintf(p, (size_t)(end - p), "|DE");
229 229 if (mxcsr & SSE_ZE)
230 230 p += mdb_snprintf(p, (size_t)(end - p), "|ZE");
231 231 if (mxcsr & SSE_OE)
232 232 p += mdb_snprintf(p, (size_t)(end - p), "|OE");
233 233 if (mxcsr & SSE_UE)
234 234 p += mdb_snprintf(p, (size_t)(end - p), "|UE");
235 235 if (mxcsr & SSE_PE)
236 236 p += mdb_snprintf(p, (size_t)(end - p), "|PE");
237 237
238 238 if (mxcsr & SSE_DAZ)
239 239 p += mdb_snprintf(p, (size_t)(end - p), "|DAZ");
240 240
241 241 if (mxcsr & SSE_IM)
242 242 p += mdb_snprintf(p, (size_t)(end - p), "|IM");
243 243 if (mxcsr & SSE_DM)
244 244 p += mdb_snprintf(p, (size_t)(end - p), "|DM");
245 245 if (mxcsr & SSE_ZM)
246 246 p += mdb_snprintf(p, (size_t)(end - p), "|ZM");
247 247 if (mxcsr & SSE_OM)
248 248 p += mdb_snprintf(p, (size_t)(end - p), "|OM");
249 249 if (mxcsr & SSE_UM)
250 250 p += mdb_snprintf(p, (size_t)(end - p), "|UM");
251 251 if (mxcsr & SSE_PM)
252 252 p += mdb_snprintf(p, (size_t)(end - p), "|PM");
253 253
254 254 if ((mxcsr & SSE_RC) == (SSE_RD|SSE_RU))
255 255 p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
256 256 else if (mxcsr & SSE_RD)
257 257 p += mdb_snprintf(p, (size_t)(end - p), "|RD");
258 258 else if (mxcsr & SSE_RU)
259 259 p += mdb_snprintf(p, (size_t)(end - p), "|RU");
260 260 else
261 261 p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
262 262
263 263 if (mxcsr & SSE_FZ)
264 264 p += mdb_snprintf(p, (size_t)(end - p), "|FZ");
265 265
266 266 if (buf[0] == '|')
267 267 return (buf + 1);
268 268 return ("0");
269 269 }
270 270
271 271 const char *
272 272 fptag2str(uint32_t val)
273 273 {
274 274 /*
275 275 * Array of strings corresponding to FPU tag word values (see
276 276 * section 7.3.6 of the Intel Programmer's Reference Manual).
277 277 */
278 278 const char *tag_strings[] = { "valid", "zero", "special", "empty" };
279 279
280 280 if (val >= ARRAY_SIZE(tag_strings)) {
281 281 return ("unknown");
282 282 }
283 283
284 284 return (tag_strings[val]);
285 285 }
286 286
287 287 static uintptr_t
288 288 xregs_data_ptr(const prxregset_hdr_t *prx, const prxregset_info_t *info)
289 289 {
290 290 uintptr_t base = (uintptr_t)prx;
291 291 return (base + info->pri_offset);
292 292 }
293 293
294 294 static boolean_t
295 295 xregs_valid_data(const prxregset_hdr_t *prx, const prxregset_info_t *info,
296 296 size_t exp_size, const char *type)
297 297 {
298 298 size_t last_byte;
299 299
300 300 if (info->pri_size != exp_size) {
301 301 mdb_warn("%s has unexpeced size 0x%lx, expected 0x%lx -- "
302 302 "cannot use\n", type, info->pri_size, exp_size);
303 303 return (B_FALSE);
304 304 }
305 305
306 306 last_byte = (size_t)info->pri_size + (size_t)info->pri_offset;
307 307 if (last_byte < MIN(info->pri_size, info->pri_offset)) {
308 308 mdb_warn("%s size 0x%lx and offset 0x%lx appear to overflow -- "
309 309 "canot use\n", type, info->pri_size, info->pri_offset);
310 310 return (B_FALSE);
311 311 }
312 312
313 313 return (B_TRUE);
314 314 }
315 315
316 316 static const char *
317 317 fp_type_to_str(x86_vector_type_t type)
318 318 {
319 319 switch (type) {
320 320 case XMM:
321 321 return ("128-bit %xmm");
322 322 case YMM:
323 323 return ("256-bit %ymm");
324 324 case ZMM:
325 325 return ("512-bit %zmm");
326 326 default:
327 327 return ("unknown");
328 328 }
329 329 }
330 330
331 331 /*
332 332 * Go through the xregs data that we have and make sure that it makes sense for
333 333 * printing. In particular we need to make sure:
334 334 *
335 335 * o The structure type is what we expect
336 336 * o That its overall size is correct
337 337 * o That we can find the expected set of data pointers that should be here
338 338 * o That the information pointers actually make sense and their contents are
339 339 * both the correct size and within the overall structure. Note, we do not
340 340 * check for overlapping data regions right now, meaning that some weird
341 341 * notes may still lead to weird data.
342 342 */
343 343 static boolean_t
344 344 pt_xregs_process(const prxregset_hdr_t *prx, size_t found_size,
345 345 x86_xregs_info_t *xinfo)
346 346 {
347 347 bzero(xinfo, sizeof (*xinfo));
348 348
349 349 if (prx->pr_type != PR_TYPE_XSAVE) {
350 350 mdb_warn("prxregset has unknown type: 0x%x\n -- falling back "
351 351 "to fpregset_t\n", prx->pr_type);
352 352 return (B_FALSE);
353 353 }
354 354
355 355 if (prx->pr_size < found_size) {
356 356 mdb_warn("prxregset has greater size than we were given: "
357 357 "found 0x%lx, have 0x%lx\n", prx->pr_size, found_size);
358 358 return (B_FALSE);
359 359 }
360 360
361 361 for (uint32_t i = 0; i < prx->pr_ninfo; i++) {
362 362 switch (prx->pr_info[i].pri_type) {
363 363 case PRX_INFO_XCR:
364 364 if (xregs_valid_data(prx, &prx->pr_info[i],
365 365 sizeof (prxregset_xcr_t), "xcr")) {
366 366 xinfo->xri_xcr = (void *)xregs_data_ptr(prx,
367 367 &prx->pr_info[i]);
368 368 }
369 369 break;
370 370 case PRX_INFO_XSAVE:
371 371 if (xregs_valid_data(prx, &prx->pr_info[i],
372 372 sizeof (prxregset_xsave_t), "xsave")) {
373 373 xinfo->xri_xsave = (void *)xregs_data_ptr(prx,
374 374 &prx->pr_info[i]);
375 375 }
376 376 break;
377 377 case PRX_INFO_YMM:
378 378 if (xregs_valid_data(prx, &prx->pr_info[i],
379 379 sizeof (prxregset_ymm_t), "ymm")) {
380 380 xinfo->xri_ymm = (void *)xregs_data_ptr(prx,
381 381 &prx->pr_info[i]);
382 382 }
383 383 break;
384 384 case PRX_INFO_OPMASK:
385 385 if (xregs_valid_data(prx, &prx->pr_info[i],
386 386 sizeof (prxregset_opmask_t), "opmask")) {
387 387 xinfo->xri_opmask = (void *)xregs_data_ptr(prx,
388 388 &prx->pr_info[i]);
389 389 }
390 390 break;
391 391 case PRX_INFO_ZMM:
392 392 if (xregs_valid_data(prx, &prx->pr_info[i],
393 393 sizeof (prxregset_zmm_t), "zmm")) {
394 394 xinfo->xri_zmm = (void *)xregs_data_ptr(prx,
395 395 &prx->pr_info[i]);
396 396 }
397 397 break;
398 398 case PRX_INFO_HI_ZMM:
399 399 if (xregs_valid_data(prx, &prx->pr_info[i],
400 400 sizeof (prxregset_hi_zmm_t), "hi_zmm")) {
401 401 xinfo->xri_hi_zmm = (void *)xregs_data_ptr(prx,
402 402 &prx->pr_info[i]);
403 403 }
404 404 break;
405 405 default:
406 406 mdb_warn("ignoring unexpected xreg info type: 0x%x\n",
407 407 prx->pr_info[i].pri_type);
408 408 break;
409 409 }
410 410 }
411 411
412 412 /*
413 413 * Now that we have gotten this far, we go and figure out what the
414 414 * largest type of information we actually have is. We check from the
415 415 * simplest to the most complex as to see the more complex state
416 416 * requires having the more basic state, due to how Intel designed the
417 417 * xsave state.
418 418 */
419 419 if (xinfo->xri_xsave == NULL) {
420 420 mdb_warn("missing required xsave information: xregs not "
421 421 "usable\n");
422 422 return (B_FALSE);
423 423 }
424 424
425 425 xinfo->xri_type = XMM;
426 426 if (xinfo->xri_ymm != NULL) {
427 427 uint_t nzmm = 0;
428 428 if (xinfo->xri_opmask != NULL)
429 429 nzmm++;
430 430 if (xinfo->xri_zmm != NULL)
431 431 nzmm++;
432 432 if (xinfo->xri_hi_zmm != NULL)
433 433 nzmm++;
434 434 if (nzmm == 3) {
435 435 xinfo->xri_type = ZMM;
436 436 } else if (nzmm == 0) {
437 437 xinfo->xri_type = YMM;
438 438 } else {
439 439 mdb_warn("encountered mismatched AVX-512 components, "
440 440 "defaulting back to YMM\n");
441 441 mdb_warn("found opmask %s, zmm %s, hi zmm %s\n",
442 442 xinfo->xri_opmask != NULL ? "present" : "missing",
443 443 xinfo->xri_zmm != NULL ? "present" : "missing",
444 444 xinfo->xri_hi_zmm != NULL ? "present" : "missing");
445 445 }
446 446 }
447 447
448 448 return (B_TRUE);
449 449 }
450 450
451 451 static void
452 452 pt_xreg_single_vector(const upad128_t *xmm, const upad128_t *ymm,
453 453 const upad256_t *zmm, uint32_t num)
454 454 {
455 455
456 456 if (zmm != NULL) {
457 457 mdb_printf("%%zmm%u%s[511:384] 0x%08x %08x %08x %08x\n"
458 458 " [383:256] 0x%08x %08x %08x %08x\n", num,
459 459 num >= 10 ? " " : " ",
460 460 zmm->_l[7], zmm->_l[6], zmm->_l[5], zmm->_l[4],
461 461 zmm->_l[3], zmm->_l[2], zmm->_l[1], zmm->_l[0]);
462 462 }
463 463
464 464 if (ymm != NULL) {
465 465 mdb_printf("%%ymm%u%s[255:128] 0x%08x %08x %08x %08x\n",
466 466 num, num >= 10 ? " " : " ",
467 467 ymm->_l[3], ymm->_l[2], ymm->_l[1], ymm->_l[0]);
468 468 }
469 469
470 470 if (xmm != NULL) {
471 471 mdb_printf("%%xmm%u%s[127:0] 0x%08x %08x %08x %08x\n",
472 472 num, num >= 10 ? " " : " ",
473 473 xmm->_l[3], xmm->_l[2], xmm->_l[1], xmm->_l[0]);
474 474 }
475 475
476 476 /*
477 477 * Insert output spacing if we exceed more than one line which happens
478 478 * if ymm state is present.
479 479 */
480 480 if (ymm != NULL) {
481 481 mdb_printf("\n");
482 482 }
483 483 }
484 484
485 485 /*
486 486 * Variant of the above, but all of the data is one single register. This is
487 487 * only used for the high zmm registers which are only present on amd64.
488 488 */
489 489 #ifdef __amd64
490 490 static void
491 491 pt_xreg_single_u512(const upad512_t *zmm, uint32_t num)
492 492 {
493 493 mdb_printf("%%zmm%u%s[511:384] 0x%08x %08x %08x %08x\n"
494 494 " [383:256] 0x%08x %08x %08x %08x\n", num,
495 495 num >= 10 ? " " : " ",
496 496 zmm->_l[15], zmm->_l[14], zmm->_l[13], zmm->_l[12],
497 497 zmm->_l[11], zmm->_l[10], zmm->_l[9], zmm->_l[8]);
498 498
499 499 mdb_printf("%%zmm%u%s[255:128] 0x%08x %08x %08x %08x\n",
500 500 num, num >= 10 ? " " : " ",
501 501 zmm->_l[7], zmm->_l[6], zmm->_l[5], zmm->_l[4]);
502 502
503 503 mdb_printf("%%zmm%u%s[127:0] 0x%08x %08x %08x %08x\n",
504 504 num, num >= 10 ? " " : " ",
505 505 zmm->_l[3], zmm->_l[2], zmm->_l[1], zmm->_l[0]);
506 506
507 507 mdb_printf("\n");
508 508 }
509 509 #endif /* __amd64 */
510 510
511 511 /*
512 512 * There are two different cases that we need to consider for vector printing.
513 513 * The first 16 FPU registers are shadowed as the low bits of xmm0 overlap with
514 514 * ymm0, overlap with zmm0.
515 515 */
516 516 static void
517 517 pt_xregs_vectors(const x86_xregs_info_t *xinfo)
518 518 {
519 519 size_t nregs = ARRAY_SIZE(xinfo->xri_xsave->prx_fx_xmm);
520 520 for (size_t i = 0; i < nregs; i++) {
521 521 switch (xinfo->xri_type) {
522 522 case XMM:
523 523 pt_xreg_single_vector(&xinfo->xri_xsave->prx_fx_xmm[i],
524 524 NULL, NULL, i);
525 525 break;
526 526 case YMM:
527 527 pt_xreg_single_vector(&xinfo->xri_xsave->prx_fx_xmm[i],
528 528 &xinfo->xri_ymm->prx_ymm[i], NULL, i);
529 529 break;
530 530 case ZMM:
531 531 pt_xreg_single_vector(&xinfo->xri_xsave->prx_fx_xmm[i],
532 532 &xinfo->xri_ymm->prx_ymm[i],
533 533 &xinfo->xri_zmm->prx_zmm[i], i);
534 534 break;
535 535 }
536 536 }
537 537
538 538 /*
539 539 * If we have ZMM state, next print the remaining 16 registers and then
540 540 * the 8 opmask registers. Note, we only have the high ZMM registers on
541 541 * 64-bit processes.
542 542 */
543 543 if (xinfo->xri_type == ZMM) {
544 544 #ifdef __amd64
545 545 nregs = ARRAY_SIZE(xinfo->xri_hi_zmm->prx_hi_zmm);
546 546 for (size_t i = 0; i < nregs; i++) {
547 547 pt_xreg_single_u512(&xinfo->xri_hi_zmm->prx_hi_zmm[i],
548 548 i + 16);
549 549 }
550 550 #endif /* __amd64 */
551 551
552 552 mdb_printf("%%k0 0x%016x\t\t%%k1 0x%016x\n",
553 553 xinfo->xri_opmask->prx_opmask[0],
554 554 xinfo->xri_opmask->prx_opmask[1]);
555 555 mdb_printf("%%k2 0x%016x\t\t%%k3 0x%016x\n",
556 556 xinfo->xri_opmask->prx_opmask[2],
557 557 xinfo->xri_opmask->prx_opmask[3]);
558 558 mdb_printf("%%k4 0x%016x\t\t%%k5 0x%016x\n",
559 559 xinfo->xri_opmask->prx_opmask[4],
560 560 xinfo->xri_opmask->prx_opmask[5]);
561 561 mdb_printf("%%k6 0x%016x\t\t%%k7 0x%016x\n",
562 562 xinfo->xri_opmask->prx_opmask[6],
563 563 xinfo->xri_opmask->prx_opmask[7]);
564 564
565 565 mdb_printf("\n");
566 566 }
567 567 }
568 568
569 569 int
570 570 x86_pt_fpregs_common(uintptr_t addr, uint_t flags, int argc,
571 571 prfpregset_t *fprsp)
572 572 {
573 573 mdb_tgt_t *t = mdb.m_target;
574 574 mdb_tgt_tid_t tid;
575 575 prxregset_t *xregs = NULL;
576 576 size_t xregsize = 0;
577 577 x86_xregs_info_t xinfo;
578 578 x86_vector_type_t vector_type = XMM;
579 579
580 580 if (argc != 0)
581 581 return (DCMD_USAGE);
582 582
583 583 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
584 584 mdb_warn("no process active\n");
585 585 return (DCMD_ERR);
586 586 }
587 587
588 588 if (Pstate(t->t_pshandle) == PS_LOST) {
589 589 mdb_warn("debugger has lost control of process\n");
590 590 return (DCMD_ERR);
591 591 }
592 592
593 593 if (flags & DCMD_ADDRSPEC)
594 594 tid = (mdb_tgt_tid_t)addr;
595 595 else
596 596 tid = PTL_TID(t);
597 597
598 598 /*
599 599 * We ultimately need both the xregs and the fpregs. The fpregs have
600 600 * included synthetic-kernel created state that is not part of the FPU
601 601 * (the status / xstatus bits). If we find the xregs state, then we
602 602 * focus on using its data in lieu of the standard fxsave piece.
603 603 */
604 604 if (PTL_GETFPREGS(t, tid, fprsp) != 0) {
605 605 mdb_warn("failed to get floating point registers");
606 606 return (DCMD_ERR);
607 607 }
608 608
609 609 bzero(&xinfo, sizeof (x86_xregs_info_t));
610 610 if (PTL_GETXREGS(t, tid, &xregs, &xregsize) == 0) {
611 611 prxregset_hdr_t *prx = (prxregset_hdr_t *)xregs;
612 612 if (!pt_xregs_process(prx, xregsize, &xinfo)) {
613 613 PTL_FREEXREGS(t, xregs, xregsize);
614 614 xregs = NULL;
615 615 } else {
616 616 vector_type = xinfo.xri_type;
617 617 }
618 618 } else if (errno != ENOENT && errno != ENODATA && errno != ENOTSUP) {
619 619 mdb_warn("failed to get xregs");
620 620 }
621 621
622 622 /*
623 623 * We ultimately need both the xregs and the fpregs. The fpregs have
624 624 * included synthetic-kernel created state that is not part of the FPU
625 625 * (the status / xstatus bits). If we find the xregs state, then we
626 626 * focus on using its data in lieu of the standard fxsave piece.
627 627 */
628 628 if (PTL_GETFPREGS(t, tid, fprsp) != 0) {
629 629 mdb_warn("failed to get floating point registers");
630 630 return (DCMD_ERR);
631 631 }
632 632
633 633 bzero(&xinfo, sizeof (x86_xregs_info_t));
634 634 if (PTL_GETXREGS(t, tid, &xregs, &xregsize) == 0) {
635 635 prxregset_hdr_t *prx = (prxregset_hdr_t *)xregs;
636 636 if (!pt_xregs_process(prx, xregsize, &xinfo)) {
637 637 PTL_FREEXREGS(t, xregs, xregsize);
638 638 xregs = NULL;
639 639 } else {
640 640 vector_type = xinfo.xri_type;
641 641 }
642 642 } else if (errno != ENOENT && errno != ENODATA && errno != ENOTSUP) {
643 643 mdb_warn("failed to get xregs");
644 644 }
645 645
646 646 /*
647 647 * As we only support the amd64 kernel, we basically phrase the FPU the
648 648 * same way regardless of whether it is 32-bit or 64-bit now.
649 649 */
650 650 mdb_printf("x86 FPU with %s registers\n", fp_type_to_str(vector_type));
651 651 if (xinfo.xri_xcr != NULL) {
652 652 mdb_printf("xcr0\t\t0x%lx\n", xinfo.xri_xcr->prx_xcr_xcr0);
653 653 mdb_printf("xfd\t\t0x%lx\n", xinfo.xri_xcr->prx_xcr_xfd);
654 654 }
655 655
656 656 if (xinfo.xri_xsave != NULL) {
657 657 mdb_printf("xstate_bv\t0x%lx\n",
658 658 xinfo.xri_xsave->prx_xsh_xstate_bv);
659 659 mdb_printf("xcomp_bv\t0x%lx\n",
660 660 xinfo.xri_xsave->prx_xsh_xcomp_bv);
661 661
662 662 mdb_printf("\n");
663 663 /*
664 664 * xsave is required for us to use the xregset, so from here as
665 665 * it to print vectors.
666 666 */
667 667 pt_xregs_vectors(&xinfo);
668 668 } else {
669 669 size_t nregs = ARRAY_SIZE(fprsp->fp_reg_set.fpchip_state.xmm);
670 670 for (uint32_t i = 0; i < nregs; i++) {
671 671 const upad128_t *u128 =
672 672 &fprsp->fp_reg_set.fpchip_state.xmm[i];
673 673 pt_xreg_single_vector(u128, NULL, NULL, i);
674 674 }
675 675
676 676 mdb_printf("\n");
677 677 }
678 678
679 679 if (xregs != NULL) {
680 680 PTL_FREEXREGS(t, xregs, xregsize);
681 681 }
682 682
683 683 return (DCMD_OK);
684 684 }
685 685
686 686 void
687 687 x86_pt_fpregs_sse_ctl(uint32_t mxcsr, uint32_t xstatus, char *buf,
688 688 size_t buflen)
689 689 {
690 690 mdb_printf("\nSSE Control State\n");
691 691 mdb_printf("mxcsr 0x%04x (%s)\n", mxcsr,
692 692 fpmxcsr2str(mxcsr, buf, buflen));
693 693 mdb_printf("xcp 0x%04x (%s)\n", xstatus,
694 694 fpmxcsr2str(xstatus, buf, buflen));
695 695 }
|
↓ open down ↓ |
695 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX