1 //===-- DNBArchImplI386.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Greg Clayton on 6/25/07.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #if defined(__i386__) || defined(__x86_64__)
15 
16 #include <sys/cdefs.h>
17 
18 #include "DNBLog.h"
19 #include "MacOSX/i386/DNBArchImplI386.h"
20 #include "MachProcess.h"
21 #include "MachThread.h"
22 
23 extern "C" bool CPUHasAVX(); // Defined over in DNBArchImplX86_64.cpp
24 
25 #if defined(LLDB_DEBUGSERVER_RELEASE) || defined(LLDB_DEBUGSERVER_DEBUG)
26 enum debugState { debugStateUnknown, debugStateOff, debugStateOn };
27 
28 static debugState sFPUDebugState = debugStateUnknown;
29 static debugState sAVXForceState = debugStateUnknown;
30 
31 static bool DebugFPURegs() {
32   if (sFPUDebugState == debugStateUnknown) {
33     if (getenv("DNB_DEBUG_FPU_REGS"))
34       sFPUDebugState = debugStateOn;
35     else
36       sFPUDebugState = debugStateOff;
37   }
38 
39   return (sFPUDebugState == debugStateOn);
40 }
41 
42 static bool ForceAVXRegs() {
43   if (sFPUDebugState == debugStateUnknown) {
44     if (getenv("DNB_DEBUG_X86_FORCE_AVX_REGS"))
45       sAVXForceState = debugStateOn;
46     else
47       sAVXForceState = debugStateOff;
48   }
49 
50   return (sAVXForceState == debugStateOn);
51 }
52 
53 #define DEBUG_FPU_REGS (DebugFPURegs())
54 #define FORCE_AVX_REGS (ForceAVXRegs())
55 #else
56 #define DEBUG_FPU_REGS (0)
57 #define FORCE_AVX_REGS (0)
58 #endif
59 
60 enum {
61   gpr_eax = 0,
62   gpr_ebx = 1,
63   gpr_ecx = 2,
64   gpr_edx = 3,
65   gpr_edi = 4,
66   gpr_esi = 5,
67   gpr_ebp = 6,
68   gpr_esp = 7,
69   gpr_ss = 8,
70   gpr_eflags = 9,
71   gpr_eip = 10,
72   gpr_cs = 11,
73   gpr_ds = 12,
74   gpr_es = 13,
75   gpr_fs = 14,
76   gpr_gs = 15,
77   gpr_ax,
78   gpr_bx,
79   gpr_cx,
80   gpr_dx,
81   gpr_di,
82   gpr_si,
83   gpr_bp,
84   gpr_sp,
85   gpr_ah,
86   gpr_bh,
87   gpr_ch,
88   gpr_dh,
89   gpr_al,
90   gpr_bl,
91   gpr_cl,
92   gpr_dl,
93   gpr_dil,
94   gpr_sil,
95   gpr_bpl,
96   gpr_spl,
97   k_num_gpr_regs
98 };
99 
100 enum {
101   fpu_fcw,
102   fpu_fsw,
103   fpu_ftw,
104   fpu_fop,
105   fpu_ip,
106   fpu_cs,
107   fpu_dp,
108   fpu_ds,
109   fpu_mxcsr,
110   fpu_mxcsrmask,
111   fpu_stmm0,
112   fpu_stmm1,
113   fpu_stmm2,
114   fpu_stmm3,
115   fpu_stmm4,
116   fpu_stmm5,
117   fpu_stmm6,
118   fpu_stmm7,
119   fpu_xmm0,
120   fpu_xmm1,
121   fpu_xmm2,
122   fpu_xmm3,
123   fpu_xmm4,
124   fpu_xmm5,
125   fpu_xmm6,
126   fpu_xmm7,
127   fpu_ymm0,
128   fpu_ymm1,
129   fpu_ymm2,
130   fpu_ymm3,
131   fpu_ymm4,
132   fpu_ymm5,
133   fpu_ymm6,
134   fpu_ymm7,
135   k_num_fpu_regs,
136 
137   // Aliases
138   fpu_fctrl = fpu_fcw,
139   fpu_fstat = fpu_fsw,
140   fpu_ftag = fpu_ftw,
141   fpu_fiseg = fpu_cs,
142   fpu_fioff = fpu_ip,
143   fpu_foseg = fpu_ds,
144   fpu_fooff = fpu_dp
145 };
146 
147 enum {
148   exc_trapno,
149   exc_err,
150   exc_faultvaddr,
151   k_num_exc_regs,
152 };
153 
154 enum {
155   ehframe_eax = 0,
156   ehframe_ecx,
157   ehframe_edx,
158   ehframe_ebx,
159 
160   // On i386 Darwin the eh_frame register numbers for ebp and esp are reversed
161   // from DWARF.
162   // It's due to an ancient compiler bug in the output of the eh_frame.
163   // Specifically, on i386 darwin eh_frame, 4 is ebp, 5 is esp.
164   // On i386 darwin debug_frame (and debug_info), 4 is esp, 5 is ebp.
165   ehframe_ebp,
166   ehframe_esp,
167   ehframe_esi,
168   ehframe_edi,
169   ehframe_eip,
170   ehframe_eflags
171 };
172 
173 enum {
174   dwarf_eax = 0,
175   dwarf_ecx,
176   dwarf_edx,
177   dwarf_ebx,
178   dwarf_esp,
179   dwarf_ebp,
180   dwarf_esi,
181   dwarf_edi,
182   dwarf_eip,
183   dwarf_eflags,
184   dwarf_stmm0 = 11,
185   dwarf_stmm1,
186   dwarf_stmm2,
187   dwarf_stmm3,
188   dwarf_stmm4,
189   dwarf_stmm5,
190   dwarf_stmm6,
191   dwarf_stmm7,
192   dwarf_xmm0 = 21,
193   dwarf_xmm1,
194   dwarf_xmm2,
195   dwarf_xmm3,
196   dwarf_xmm4,
197   dwarf_xmm5,
198   dwarf_xmm6,
199   dwarf_xmm7,
200   dwarf_ymm0 = dwarf_xmm0,
201   dwarf_ymm1 = dwarf_xmm1,
202   dwarf_ymm2 = dwarf_xmm2,
203   dwarf_ymm3 = dwarf_xmm3,
204   dwarf_ymm4 = dwarf_xmm4,
205   dwarf_ymm5 = dwarf_xmm5,
206   dwarf_ymm6 = dwarf_xmm6,
207   dwarf_ymm7 = dwarf_xmm7,
208 };
209 
210 enum {
211   debugserver_eax = 0,
212   debugserver_ecx = 1,
213   debugserver_edx = 2,
214   debugserver_ebx = 3,
215   debugserver_esp = 4,
216   debugserver_ebp = 5,
217   debugserver_esi = 6,
218   debugserver_edi = 7,
219   debugserver_eip = 8,
220   debugserver_eflags = 9,
221   debugserver_cs = 10,
222   debugserver_ss = 11,
223   debugserver_ds = 12,
224   debugserver_es = 13,
225   debugserver_fs = 14,
226   debugserver_gs = 15,
227   debugserver_stmm0 = 16,
228   debugserver_stmm1 = 17,
229   debugserver_stmm2 = 18,
230   debugserver_stmm3 = 19,
231   debugserver_stmm4 = 20,
232   debugserver_stmm5 = 21,
233   debugserver_stmm6 = 22,
234   debugserver_stmm7 = 23,
235   debugserver_fctrl = 24,
236   debugserver_fcw = debugserver_fctrl,
237   debugserver_fstat = 25,
238   debugserver_fsw = debugserver_fstat,
239   debugserver_ftag = 26,
240   debugserver_ftw = debugserver_ftag,
241   debugserver_fiseg = 27,
242   debugserver_fpu_cs = debugserver_fiseg,
243   debugserver_fioff = 28,
244   debugserver_ip = debugserver_fioff,
245   debugserver_foseg = 29,
246   debugserver_fpu_ds = debugserver_foseg,
247   debugserver_fooff = 30,
248   debugserver_dp = debugserver_fooff,
249   debugserver_fop = 31,
250   debugserver_xmm0 = 32,
251   debugserver_xmm1 = 33,
252   debugserver_xmm2 = 34,
253   debugserver_xmm3 = 35,
254   debugserver_xmm4 = 36,
255   debugserver_xmm5 = 37,
256   debugserver_xmm6 = 38,
257   debugserver_xmm7 = 39,
258   debugserver_mxcsr = 40,
259   debugserver_mm0 = 41,
260   debugserver_mm1 = 42,
261   debugserver_mm2 = 43,
262   debugserver_mm3 = 44,
263   debugserver_mm4 = 45,
264   debugserver_mm5 = 46,
265   debugserver_mm6 = 47,
266   debugserver_mm7 = 48,
267   debugserver_ymm0 = debugserver_xmm0,
268   debugserver_ymm1 = debugserver_xmm1,
269   debugserver_ymm2 = debugserver_xmm2,
270   debugserver_ymm3 = debugserver_xmm3,
271   debugserver_ymm4 = debugserver_xmm4,
272   debugserver_ymm5 = debugserver_xmm5,
273   debugserver_ymm6 = debugserver_xmm6,
274   debugserver_ymm7 = debugserver_xmm7
275 };
276 
277 uint64_t DNBArchImplI386::GetPC(uint64_t failValue) {
278   // Get program counter
279   if (GetGPRState(false) == KERN_SUCCESS)
280     return m_state.context.gpr.__eip;
281   return failValue;
282 }
283 
284 kern_return_t DNBArchImplI386::SetPC(uint64_t value) {
285   // Get program counter
286   kern_return_t err = GetGPRState(false);
287   if (err == KERN_SUCCESS) {
288     m_state.context.gpr.__eip = static_cast<uint32_t>(value);
289     err = SetGPRState();
290   }
291   return err == KERN_SUCCESS;
292 }
293 
294 uint64_t DNBArchImplI386::GetSP(uint64_t failValue) {
295   // Get stack pointer
296   if (GetGPRState(false) == KERN_SUCCESS)
297     return m_state.context.gpr.__esp;
298   return failValue;
299 }
300 
301 // Uncomment the value below to verify the values in the debugger.
302 //#define DEBUG_GPR_VALUES 1    // DO NOT CHECK IN WITH THIS DEFINE ENABLED
303 //#define SET_GPR(reg) m_state.context.gpr.__##reg = gpr_##reg
304 
305 kern_return_t DNBArchImplI386::GetGPRState(bool force) {
306   if (force || m_state.GetError(e_regSetGPR, Read)) {
307 #if DEBUG_GPR_VALUES
308     SET_GPR(eax);
309     SET_GPR(ebx);
310     SET_GPR(ecx);
311     SET_GPR(edx);
312     SET_GPR(edi);
313     SET_GPR(esi);
314     SET_GPR(ebp);
315     SET_GPR(esp);
316     SET_GPR(ss);
317     SET_GPR(eflags);
318     SET_GPR(eip);
319     SET_GPR(cs);
320     SET_GPR(ds);
321     SET_GPR(es);
322     SET_GPR(fs);
323     SET_GPR(gs);
324     m_state.SetError(e_regSetGPR, Read, 0);
325 #else
326     mach_msg_type_number_t count = e_regSetWordSizeGPR;
327     m_state.SetError(
328         e_regSetGPR, Read,
329         ::thread_get_state(m_thread->MachPortNumber(), __i386_THREAD_STATE,
330                            (thread_state_t)&m_state.context.gpr, &count));
331 #endif
332   }
333   return m_state.GetError(e_regSetGPR, Read);
334 }
335 
336 // Uncomment the value below to verify the values in the debugger.
337 //#define DEBUG_FPU_VALUES 1    // DO NOT CHECK IN WITH THIS DEFINE ENABLED
338 
339 kern_return_t DNBArchImplI386::GetFPUState(bool force) {
340   if (force || m_state.GetError(e_regSetFPU, Read)) {
341     if (DEBUG_FPU_REGS) {
342 
343       m_state.context.fpu.no_avx.__fpu_reserved[0] = -1;
344       m_state.context.fpu.no_avx.__fpu_reserved[1] = -1;
345       *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fcw) = 0x1234;
346       *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fsw) = 0x5678;
347       m_state.context.fpu.no_avx.__fpu_ftw = 1;
348       m_state.context.fpu.no_avx.__fpu_rsrv1 = UINT8_MAX;
349       m_state.context.fpu.no_avx.__fpu_fop = 2;
350       m_state.context.fpu.no_avx.__fpu_ip = 3;
351       m_state.context.fpu.no_avx.__fpu_cs = 4;
352       m_state.context.fpu.no_avx.__fpu_rsrv2 = 5;
353       m_state.context.fpu.no_avx.__fpu_dp = 6;
354       m_state.context.fpu.no_avx.__fpu_ds = 7;
355       m_state.context.fpu.no_avx.__fpu_rsrv3 = UINT16_MAX;
356       m_state.context.fpu.no_avx.__fpu_mxcsr = 8;
357       m_state.context.fpu.no_avx.__fpu_mxcsrmask = 9;
358       for (int i = 0; i < 16; ++i) {
359         if (i < 10) {
360           m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = 'a';
361           m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = 'b';
362           m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = 'c';
363           m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = 'd';
364           m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = 'e';
365           m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = 'f';
366           m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = 'g';
367           m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = 'h';
368         } else {
369           m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN;
370           m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN;
371           m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN;
372           m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN;
373           m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN;
374           m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN;
375           m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN;
376           m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN;
377         }
378 
379         m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg[i] = '0';
380         m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg[i] = '1';
381         m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg[i] = '2';
382         m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg[i] = '3';
383         m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg[i] = '4';
384         m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg[i] = '5';
385         m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg[i] = '6';
386         m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg[i] = '7';
387       }
388       for (int i = 0; i < sizeof(m_state.context.fpu.no_avx.__fpu_rsrv4); ++i)
389         m_state.context.fpu.no_avx.__fpu_rsrv4[i] = INT8_MIN;
390       m_state.context.fpu.no_avx.__fpu_reserved1 = -1;
391 
392       if (CPUHasAVX() || FORCE_AVX_REGS) {
393         for (int i = 0; i < sizeof(m_state.context.fpu.avx.__avx_reserved1); ++i)
394           m_state.context.fpu.avx.__avx_reserved1[i] = INT8_MIN;
395 
396         for (int i = 0; i < 16; ++i) {
397           m_state.context.fpu.avx.__fpu_ymmh0.__xmm_reg[i] = '0';
398           m_state.context.fpu.avx.__fpu_ymmh1.__xmm_reg[i] = '1';
399           m_state.context.fpu.avx.__fpu_ymmh2.__xmm_reg[i] = '2';
400           m_state.context.fpu.avx.__fpu_ymmh3.__xmm_reg[i] = '3';
401           m_state.context.fpu.avx.__fpu_ymmh4.__xmm_reg[i] = '4';
402           m_state.context.fpu.avx.__fpu_ymmh5.__xmm_reg[i] = '5';
403           m_state.context.fpu.avx.__fpu_ymmh6.__xmm_reg[i] = '6';
404           m_state.context.fpu.avx.__fpu_ymmh7.__xmm_reg[i] = '7';
405         }
406       }
407       m_state.SetError(e_regSetFPU, Read, 0);
408     } else {
409       mach_msg_type_number_t count = e_regSetWordSizeFPU;
410       int flavor = __i386_FLOAT_STATE;
411 
412       if (CPUHasAVX() || FORCE_AVX_REGS) {
413         count = e_regSetWordSizeAVX;
414         flavor = __i386_AVX_STATE;
415       }
416       m_state.SetError(e_regSetFPU, Read,
417                        ::thread_get_state(m_thread->MachPortNumber(), flavor,
418                                           (thread_state_t)&m_state.context.fpu,
419                                           &count));
420       DNBLogThreadedIf(LOG_THREAD,
421                        "::thread_get_state (0x%4.4x, %u, &fpu, %u => 0x%8.8x",
422                        m_thread->MachPortNumber(), flavor, (uint32_t)count,
423                        m_state.GetError(e_regSetFPU, Read));
424     }
425   }
426   return m_state.GetError(e_regSetFPU, Read);
427 }
428 
429 kern_return_t DNBArchImplI386::GetEXCState(bool force) {
430   if (force || m_state.GetError(e_regSetEXC, Read)) {
431     mach_msg_type_number_t count = e_regSetWordSizeEXC;
432     m_state.SetError(
433         e_regSetEXC, Read,
434         ::thread_get_state(m_thread->MachPortNumber(), __i386_EXCEPTION_STATE,
435                            (thread_state_t)&m_state.context.exc, &count));
436   }
437   return m_state.GetError(e_regSetEXC, Read);
438 }
439 
440 kern_return_t DNBArchImplI386::SetGPRState() {
441   kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
442   DNBLogThreadedIf(
443       LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u "
444                   "(SetGPRState() for stop_count = %u)",
445       m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
446 
447   m_state.SetError(e_regSetGPR, Write,
448                    ::thread_set_state(m_thread->MachPortNumber(),
449                                       __i386_THREAD_STATE,
450                                       (thread_state_t)&m_state.context.gpr,
451                                       e_regSetWordSizeGPR));
452   return m_state.GetError(e_regSetGPR, Write);
453 }
454 
455 kern_return_t DNBArchImplI386::SetFPUState() {
456   if (DEBUG_FPU_REGS) {
457     m_state.SetError(e_regSetFPU, Write, 0);
458     return m_state.GetError(e_regSetFPU, Write);
459   } else {
460     if (CPUHasAVX() || FORCE_AVX_REGS)
461       m_state.SetError(
462           e_regSetFPU, Write,
463           ::thread_set_state(m_thread->MachPortNumber(), __i386_AVX_STATE,
464                              (thread_state_t)&m_state.context.fpu.avx,
465                              e_regSetWordSizeAVX));
466     else
467       m_state.SetError(
468           e_regSetFPU, Write,
469           ::thread_set_state(m_thread->MachPortNumber(), __i386_FLOAT_STATE,
470                              (thread_state_t)&m_state.context.fpu.no_avx,
471                              e_regSetWordSizeFPU));
472     return m_state.GetError(e_regSetFPU, Write);
473   }
474 }
475 
476 kern_return_t DNBArchImplI386::SetEXCState() {
477   m_state.SetError(e_regSetEXC, Write,
478                    ::thread_set_state(m_thread->MachPortNumber(),
479                                       __i386_EXCEPTION_STATE,
480                                       (thread_state_t)&m_state.context.exc,
481                                       e_regSetWordSizeEXC));
482   return m_state.GetError(e_regSetEXC, Write);
483 }
484 
485 kern_return_t DNBArchImplI386::GetDBGState(bool force) {
486   if (force || m_state.GetError(e_regSetDBG, Read)) {
487     mach_msg_type_number_t count = e_regSetWordSizeDBG;
488     m_state.SetError(
489         e_regSetDBG, Read,
490         ::thread_get_state(m_thread->MachPortNumber(), __i386_DEBUG_STATE,
491                            (thread_state_t)&m_state.context.dbg, &count));
492   }
493   return m_state.GetError(e_regSetDBG, Read);
494 }
495 
496 kern_return_t DNBArchImplI386::SetDBGState(bool also_set_on_task) {
497   m_state.SetError(e_regSetDBG, Write,
498                    ::thread_set_state(m_thread->MachPortNumber(),
499                                       __i386_DEBUG_STATE,
500                                       (thread_state_t)&m_state.context.dbg,
501                                       e_regSetWordSizeDBG));
502   if (also_set_on_task) {
503     kern_return_t kret = ::task_set_state(
504         m_thread->Process()->Task().TaskPort(), __i386_DEBUG_STATE,
505         (thread_state_t)&m_state.context.dbg, e_regSetWordSizeDBG);
506     if (kret != KERN_SUCCESS)
507       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::SetDBGState failed "
508                                         "to set debug control register state: "
509                                         "0x%8.8x.",
510                        kret);
511   }
512   return m_state.GetError(e_regSetDBG, Write);
513 }
514 
515 void DNBArchImplI386::ThreadWillResume() {
516   // Do we need to step this thread? If so, let the mach thread tell us so.
517   if (m_thread->IsStepping()) {
518     // This is the primary thread, let the arch do anything it needs
519     EnableHardwareSingleStep(true);
520   }
521 
522   // Reset the debug status register, if necessary, before we resume.
523   kern_return_t kret = GetDBGState(false);
524   DNBLogThreadedIf(
525       LOG_WATCHPOINTS,
526       "DNBArchImplI386::ThreadWillResume() GetDBGState() => 0x%8.8x.", kret);
527   if (kret != KERN_SUCCESS)
528     return;
529 
530   DBG &debug_state = m_state.context.dbg;
531   bool need_reset = false;
532   uint32_t i, num = NumSupportedHardwareWatchpoints();
533   for (i = 0; i < num; ++i)
534     if (IsWatchpointHit(debug_state, i))
535       need_reset = true;
536 
537   if (need_reset) {
538     ClearWatchpointHits(debug_state);
539     kret = SetDBGState(false);
540     DNBLogThreadedIf(
541         LOG_WATCHPOINTS,
542         "DNBArchImplI386::ThreadWillResume() SetDBGState() => 0x%8.8x.", kret);
543   }
544 }
545 
546 bool DNBArchImplI386::ThreadDidStop() {
547   bool success = true;
548 
549   m_state.InvalidateAllRegisterStates();
550 
551   // Are we stepping a single instruction?
552   if (GetGPRState(true) == KERN_SUCCESS) {
553     // We are single stepping, was this the primary thread?
554     if (m_thread->IsStepping()) {
555       // This was the primary thread, we need to clear the trace
556       // bit if so.
557       success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
558     } else {
559       // The MachThread will automatically restore the suspend count
560       // in ThreadDidStop(), so we don't need to do anything here if
561       // we weren't the primary thread the last time
562     }
563   }
564   return success;
565 }
566 
567 bool DNBArchImplI386::NotifyException(MachException::Data &exc) {
568   switch (exc.exc_type) {
569   case EXC_BAD_ACCESS:
570     break;
571   case EXC_BAD_INSTRUCTION:
572     break;
573   case EXC_ARITHMETIC:
574     break;
575   case EXC_EMULATION:
576     break;
577   case EXC_SOFTWARE:
578     break;
579   case EXC_BREAKPOINT:
580     if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2) {
581       // exc_code = EXC_I386_BPT
582       //
583       nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS);
584       if (pc != INVALID_NUB_ADDRESS && pc > 0) {
585         pc -= 1;
586         // Check for a breakpoint at one byte prior to the current PC value
587         // since the PC will be just past the trap.
588 
589         DNBBreakpoint *bp =
590             m_thread->Process()->Breakpoints().FindByAddress(pc);
591         if (bp) {
592           // Backup the PC for i386 since the trap was taken and the PC
593           // is at the address following the single byte trap instruction.
594           if (m_state.context.gpr.__eip > 0) {
595             m_state.context.gpr.__eip = static_cast<uint32_t>(pc);
596             // Write the new PC back out
597             SetGPRState();
598           }
599         }
600         return true;
601       }
602     } else if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 1) {
603       // exc_code = EXC_I386_SGL
604       //
605       // Check whether this corresponds to a watchpoint hit event.
606       // If yes, set the exc_sub_code to the data break address.
607       nub_addr_t addr = 0;
608       uint32_t hw_index = GetHardwareWatchpointHit(addr);
609       if (hw_index != INVALID_NUB_HW_INDEX) {
610         exc.exc_data[1] = addr;
611         // Piggyback the hw_index in the exc.data.
612         exc.exc_data.push_back(hw_index);
613       }
614 
615       return true;
616     }
617     break;
618   case EXC_SYSCALL:
619     break;
620   case EXC_MACH_SYSCALL:
621     break;
622   case EXC_RPC_ALERT:
623     break;
624   }
625   return false;
626 }
627 
628 uint32_t DNBArchImplI386::NumSupportedHardwareWatchpoints() {
629   // Available debug address registers: dr0, dr1, dr2, dr3.
630   return 4;
631 }
632 
633 static uint32_t size_and_rw_bits(nub_size_t size, bool read, bool write) {
634   uint32_t rw;
635   if (read) {
636     rw = 0x3; // READ or READ/WRITE
637   } else if (write) {
638     rw = 0x1; // WRITE
639   } else {
640     assert(0 && "read and write cannot both be false");
641   }
642 
643   switch (size) {
644   case 1:
645     return rw;
646   case 2:
647     return (0x1 << 2) | rw;
648   case 4:
649     return (0x3 << 2) | rw;
650   case 8:
651     return (0x2 << 2) | rw;
652   }
653   assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
654   return 0;
655 }
656 
657 void DNBArchImplI386::SetWatchpoint(DBG &debug_state, uint32_t hw_index,
658                                     nub_addr_t addr, nub_size_t size, bool read,
659                                     bool write) {
660   // Set both dr7 (debug control register) and dri (debug address register).
661 
662   // dr7{7-0} encodes the local/gloabl enable bits:
663   //  global enable --. .-- local enable
664   //                  | |
665   //                  v v
666   //      dr0 -> bits{1-0}
667   //      dr1 -> bits{3-2}
668   //      dr2 -> bits{5-4}
669   //      dr3 -> bits{7-6}
670   //
671   // dr7{31-16} encodes the rw/len bits:
672   //  b_x+3, b_x+2, b_x+1, b_x
673   //      where bits{x+1, x} => rw
674   //            0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io
675   //            read-or-write (unused)
676   //      and bits{x+3, x+2} => len
677   //            0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
678   //
679   //      dr0 -> bits{19-16}
680   //      dr1 -> bits{23-20}
681   //      dr2 -> bits{27-24}
682   //      dr3 -> bits{31-28}
683   debug_state.__dr7 |=
684       (1 << (2 * hw_index) |
685        size_and_rw_bits(size, read, write) << (16 + 4 * hw_index));
686   uint32_t addr_32 = addr & 0xffffffff;
687   switch (hw_index) {
688   case 0:
689     debug_state.__dr0 = addr_32;
690     break;
691   case 1:
692     debug_state.__dr1 = addr_32;
693     break;
694   case 2:
695     debug_state.__dr2 = addr_32;
696     break;
697   case 3:
698     debug_state.__dr3 = addr_32;
699     break;
700   default:
701     assert(0 &&
702            "invalid hardware register index, must be one of 0, 1, 2, or 3");
703   }
704   return;
705 }
706 
707 void DNBArchImplI386::ClearWatchpoint(DBG &debug_state, uint32_t hw_index) {
708   debug_state.__dr7 &= ~(3 << (2 * hw_index));
709   switch (hw_index) {
710   case 0:
711     debug_state.__dr0 = 0;
712     break;
713   case 1:
714     debug_state.__dr1 = 0;
715     break;
716   case 2:
717     debug_state.__dr2 = 0;
718     break;
719   case 3:
720     debug_state.__dr3 = 0;
721     break;
722   default:
723     assert(0 &&
724            "invalid hardware register index, must be one of 0, 1, 2, or 3");
725   }
726   return;
727 }
728 
729 bool DNBArchImplI386::IsWatchpointVacant(const DBG &debug_state,
730                                          uint32_t hw_index) {
731   // Check dr7 (debug control register) for local/global enable bits:
732   //  global enable --. .-- local enable
733   //                  | |
734   //                  v v
735   //      dr0 -> bits{1-0}
736   //      dr1 -> bits{3-2}
737   //      dr2 -> bits{5-4}
738   //      dr3 -> bits{7-6}
739   return (debug_state.__dr7 & (3 << (2 * hw_index))) == 0;
740 }
741 
742 // Resets local copy of debug status register to wait for the next debug
743 // exception.
744 void DNBArchImplI386::ClearWatchpointHits(DBG &debug_state) {
745   // See also IsWatchpointHit().
746   debug_state.__dr6 = 0;
747   return;
748 }
749 
750 bool DNBArchImplI386::IsWatchpointHit(const DBG &debug_state,
751                                       uint32_t hw_index) {
752   // Check dr6 (debug status register) whether a watchpoint hits:
753   //          is watchpoint hit?
754   //                  |
755   //                  v
756   //      dr0 -> bits{0}
757   //      dr1 -> bits{1}
758   //      dr2 -> bits{2}
759   //      dr3 -> bits{3}
760   return (debug_state.__dr6 & (1 << hw_index));
761 }
762 
763 nub_addr_t DNBArchImplI386::GetWatchAddress(const DBG &debug_state,
764                                             uint32_t hw_index) {
765   switch (hw_index) {
766   case 0:
767     return debug_state.__dr0;
768   case 1:
769     return debug_state.__dr1;
770   case 2:
771     return debug_state.__dr2;
772   case 3:
773     return debug_state.__dr3;
774   }
775   assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3");
776   return 0;
777 }
778 
779 bool DNBArchImplI386::StartTransForHWP() {
780   if (m_2pc_trans_state != Trans_Done && m_2pc_trans_state != Trans_Rolled_Back)
781     DNBLogError("%s inconsistent state detected, expected %d or %d, got: %d",
782                 __FUNCTION__, Trans_Done, Trans_Rolled_Back, m_2pc_trans_state);
783   m_2pc_dbg_checkpoint = m_state.context.dbg;
784   m_2pc_trans_state = Trans_Pending;
785   return true;
786 }
787 bool DNBArchImplI386::RollbackTransForHWP() {
788   m_state.context.dbg = m_2pc_dbg_checkpoint;
789   if (m_2pc_trans_state != Trans_Pending)
790     DNBLogError("%s inconsistent state detected, expected %d, got: %d",
791                 __FUNCTION__, Trans_Pending, m_2pc_trans_state);
792   m_2pc_trans_state = Trans_Rolled_Back;
793   kern_return_t kret = SetDBGState(false);
794   DNBLogThreadedIf(
795       LOG_WATCHPOINTS,
796       "DNBArchImplI386::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", kret);
797 
798   if (kret == KERN_SUCCESS)
799     return true;
800   else
801     return false;
802 }
803 bool DNBArchImplI386::FinishTransForHWP() {
804   m_2pc_trans_state = Trans_Done;
805   return true;
806 }
807 DNBArchImplI386::DBG DNBArchImplI386::GetDBGCheckpoint() {
808   return m_2pc_dbg_checkpoint;
809 }
810 
811 uint32_t DNBArchImplI386::EnableHardwareWatchpoint(nub_addr_t addr,
812                                                    nub_size_t size, bool read,
813                                                    bool write,
814                                                    bool also_set_on_task) {
815   DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::EnableHardwareWatchpoint("
816                                     "addr = 0x%llx, size = %llu, read = %u, "
817                                     "write = %u)",
818                    (uint64_t)addr, (uint64_t)size, read, write);
819 
820   const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
821 
822   // Can only watch 1, 2, 4, or 8 bytes.
823   if (!(size == 1 || size == 2 || size == 4 || size == 8))
824     return INVALID_NUB_HW_INDEX;
825 
826   // We must watch for either read or write
827   if (read == false && write == false)
828     return INVALID_NUB_HW_INDEX;
829 
830   // Read the debug state
831   kern_return_t kret = GetDBGState(false);
832 
833   if (kret == KERN_SUCCESS) {
834     // Check to make sure we have the needed hardware support
835     uint32_t i = 0;
836 
837     DBG &debug_state = m_state.context.dbg;
838     for (i = 0; i < num_hw_watchpoints; ++i) {
839       if (IsWatchpointVacant(debug_state, i))
840         break;
841     }
842 
843     // See if we found an available hw breakpoint slot above
844     if (i < num_hw_watchpoints) {
845       StartTransForHWP();
846 
847       // Modify our local copy of the debug state, first.
848       SetWatchpoint(debug_state, i, addr, size, read, write);
849       // Now set the watch point in the inferior.
850       kret = SetDBGState(also_set_on_task);
851       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::"
852                                         "EnableHardwareWatchpoint() "
853                                         "SetDBGState() => 0x%8.8x.",
854                        kret);
855 
856       if (kret == KERN_SUCCESS)
857         return i;
858       else // Revert to the previous debug state voluntarily.  The transaction
859            // coordinator knows that we have failed.
860         m_state.context.dbg = GetDBGCheckpoint();
861     } else {
862       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::"
863                                         "EnableHardwareWatchpoint(): All "
864                                         "hardware resources (%u) are in use.",
865                        num_hw_watchpoints);
866     }
867   }
868   return INVALID_NUB_HW_INDEX;
869 }
870 
871 bool DNBArchImplI386::DisableHardwareWatchpoint(uint32_t hw_index,
872                                                 bool also_set_on_task) {
873   kern_return_t kret = GetDBGState(false);
874 
875   const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
876   if (kret == KERN_SUCCESS) {
877     DBG &debug_state = m_state.context.dbg;
878     if (hw_index < num_hw_points &&
879         !IsWatchpointVacant(debug_state, hw_index)) {
880       StartTransForHWP();
881 
882       // Modify our local copy of the debug state, first.
883       ClearWatchpoint(debug_state, hw_index);
884       // Now disable the watch point in the inferior.
885       kret = SetDBGState(also_set_on_task);
886       DNBLogThreadedIf(LOG_WATCHPOINTS,
887                        "DNBArchImplI386::DisableHardwareWatchpoint( %u )",
888                        hw_index);
889 
890       if (kret == KERN_SUCCESS)
891         return true;
892       else // Revert to the previous debug state voluntarily.  The transaction
893            // coordinator knows that we have failed.
894         m_state.context.dbg = GetDBGCheckpoint();
895     }
896   }
897   return false;
898 }
899 
900 // Iterate through the debug status register; return the index of the first hit.
901 uint32_t DNBArchImplI386::GetHardwareWatchpointHit(nub_addr_t &addr) {
902   // Read the debug state
903   kern_return_t kret = GetDBGState(true);
904   DNBLogThreadedIf(
905       LOG_WATCHPOINTS,
906       "DNBArchImplI386::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.",
907       kret);
908   if (kret == KERN_SUCCESS) {
909     DBG &debug_state = m_state.context.dbg;
910     uint32_t i, num = NumSupportedHardwareWatchpoints();
911     for (i = 0; i < num; ++i) {
912       if (IsWatchpointHit(debug_state, i)) {
913         addr = GetWatchAddress(debug_state, i);
914         DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::"
915                                           "GetHardwareWatchpointHit() found => "
916                                           "%u (addr = 0x%llx).",
917                          i, (uint64_t)addr);
918         return i;
919       }
920     }
921   }
922   return INVALID_NUB_HW_INDEX;
923 }
924 
925 // Set the single step bit in the processor status register.
926 kern_return_t DNBArchImplI386::EnableHardwareSingleStep(bool enable) {
927   if (GetGPRState(false) == KERN_SUCCESS) {
928     const uint32_t trace_bit = 0x100u;
929     if (enable)
930       m_state.context.gpr.__eflags |= trace_bit;
931     else
932       m_state.context.gpr.__eflags &= ~trace_bit;
933     return SetGPRState();
934   }
935   return m_state.GetError(e_regSetGPR, Read);
936 }
937 
938 //----------------------------------------------------------------------
939 // Register information definitions
940 //----------------------------------------------------------------------
941 
942 #define DEFINE_GPR_PSEUDO_16(reg16, reg32)                                     \
943   {                                                                            \
944     e_regSetGPR, gpr_##reg16, #reg16, NULL, Uint, Hex, 2, 0,                   \
945         INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,            \
946         INVALID_NUB_REGNUM, g_contained_##reg32, g_invalidate_##reg32          \
947   }
948 #define DEFINE_GPR_PSEUDO_8H(reg8, reg32)                                      \
949   {                                                                            \
950     e_regSetGPR, gpr_##reg8, #reg8, NULL, Uint, Hex, 1, 1, INVALID_NUB_REGNUM, \
951         INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,            \
952         g_contained_##reg32, g_invalidate_##reg32                              \
953   }
954 #define DEFINE_GPR_PSEUDO_8L(reg8, reg32)                                      \
955   {                                                                            \
956     e_regSetGPR, gpr_##reg8, #reg8, NULL, Uint, Hex, 1, 0, INVALID_NUB_REGNUM, \
957         INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,            \
958         g_contained_##reg32, g_invalidate_##reg32                              \
959   }
960 
961 #define GPR_OFFSET(reg) (offsetof(DNBArchImplI386::GPR, __##reg))
962 #define FPU_OFFSET(reg)                                                        \
963   (offsetof(DNBArchImplI386::FPU, __fpu_##reg) +                               \
964    offsetof(DNBArchImplI386::Context, fpu.no_avx))
965 #define AVX_OFFSET(reg)                                                        \
966   (offsetof(DNBArchImplI386::AVX, __fpu_##reg) +                               \
967    offsetof(DNBArchImplI386::Context, fpu.avx))
968 #define EXC_OFFSET(reg)                                                        \
969   (offsetof(DNBArchImplI386::EXC, __##reg) +                                   \
970    offsetof(DNBArchImplI386::Context, exc))
971 
972 #define GPR_SIZE(reg) (sizeof(((DNBArchImplI386::GPR *)NULL)->__##reg))
973 #define FPU_SIZE_UINT(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg))
974 #define FPU_SIZE_MMST(reg)                                                     \
975   (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__mmst_reg))
976 #define FPU_SIZE_XMM(reg)                                                      \
977   (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__xmm_reg))
978 #define FPU_SIZE_YMM(reg) (32)
979 #define EXC_SIZE(reg) (sizeof(((DNBArchImplI386::EXC *)NULL)->__##reg))
980 
981 // This does not accurately identify the location of ymm0...7 in
982 // Context.fpu.avx.  That is because there is a bunch of padding
983 // in Context.fpu.avx that we don't need.  Offset macros lay out
984 // the register state that Debugserver transmits to the debugger
985 // -- not to interpret the thread_get_state info.
986 #define AVX_OFFSET_YMM(n) (AVX_OFFSET(xmm7) + FPU_SIZE_XMM(xmm7) + (32 * n))
987 
988 // These macros will auto define the register name, alt name, register size,
989 // register offset, encoding, format and native register. This ensures that
990 // the register state structures are defined correctly and have the correct
991 // sizes and offsets.
992 
993 const char *g_contained_eax[] = {"eax", NULL};
994 const char *g_contained_ebx[] = {"ebx", NULL};
995 const char *g_contained_ecx[] = {"ecx", NULL};
996 const char *g_contained_edx[] = {"edx", NULL};
997 const char *g_contained_edi[] = {"edi", NULL};
998 const char *g_contained_esi[] = {"esi", NULL};
999 const char *g_contained_ebp[] = {"ebp", NULL};
1000 const char *g_contained_esp[] = {"esp", NULL};
1001 
1002 const char *g_invalidate_eax[] = {"eax", "ax", "ah", "al", NULL};
1003 const char *g_invalidate_ebx[] = {"ebx", "bx", "bh", "bl", NULL};
1004 const char *g_invalidate_ecx[] = {"ecx", "cx", "ch", "cl", NULL};
1005 const char *g_invalidate_edx[] = {"edx", "dx", "dh", "dl", NULL};
1006 const char *g_invalidate_edi[] = {"edi", "di", "dil", NULL};
1007 const char *g_invalidate_esi[] = {"esi", "si", "sil", NULL};
1008 const char *g_invalidate_ebp[] = {"ebp", "bp", "bpl", NULL};
1009 const char *g_invalidate_esp[] = {"esp", "sp", "spl", NULL};
1010 
1011 // General purpose registers for 64 bit
1012 const DNBRegisterInfo DNBArchImplI386::g_gpr_registers[] = {
1013     {e_regSetGPR, gpr_eax, "eax", NULL, Uint, Hex, GPR_SIZE(eax),
1014      GPR_OFFSET(eax), ehframe_eax, dwarf_eax, INVALID_NUB_REGNUM,
1015      debugserver_eax, NULL, g_invalidate_eax},
1016     {e_regSetGPR, gpr_ebx, "ebx", NULL, Uint, Hex, GPR_SIZE(ebx),
1017      GPR_OFFSET(ebx), ehframe_ebx, dwarf_ebx, INVALID_NUB_REGNUM,
1018      debugserver_ebx, NULL, g_invalidate_ebx},
1019     {e_regSetGPR, gpr_ecx, "ecx", NULL, Uint, Hex, GPR_SIZE(ecx),
1020      GPR_OFFSET(ecx), ehframe_ecx, dwarf_ecx, INVALID_NUB_REGNUM,
1021      debugserver_ecx, NULL, g_invalidate_ecx},
1022     {e_regSetGPR, gpr_edx, "edx", NULL, Uint, Hex, GPR_SIZE(edx),
1023      GPR_OFFSET(edx), ehframe_edx, dwarf_edx, INVALID_NUB_REGNUM,
1024      debugserver_edx, NULL, g_invalidate_edx},
1025     {e_regSetGPR, gpr_edi, "edi", NULL, Uint, Hex, GPR_SIZE(edi),
1026      GPR_OFFSET(edi), ehframe_edi, dwarf_edi, INVALID_NUB_REGNUM,
1027      debugserver_edi, NULL, g_invalidate_edi},
1028     {e_regSetGPR, gpr_esi, "esi", NULL, Uint, Hex, GPR_SIZE(esi),
1029      GPR_OFFSET(esi), ehframe_esi, dwarf_esi, INVALID_NUB_REGNUM,
1030      debugserver_esi, NULL, g_invalidate_esi},
1031     {e_regSetGPR, gpr_ebp, "ebp", "fp", Uint, Hex, GPR_SIZE(ebp),
1032      GPR_OFFSET(ebp), ehframe_ebp, dwarf_ebp, GENERIC_REGNUM_FP,
1033      debugserver_ebp, NULL, g_invalidate_ebp},
1034     {e_regSetGPR, gpr_esp, "esp", "sp", Uint, Hex, GPR_SIZE(esp),
1035      GPR_OFFSET(esp), ehframe_esp, dwarf_esp, GENERIC_REGNUM_SP,
1036      debugserver_esp, NULL, g_invalidate_esp},
1037     {e_regSetGPR, gpr_ss, "ss", NULL, Uint, Hex, GPR_SIZE(ss), GPR_OFFSET(ss),
1038      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_ss,
1039      NULL, NULL},
1040     {e_regSetGPR, gpr_eflags, "eflags", "flags", Uint, Hex, GPR_SIZE(eflags),
1041      GPR_OFFSET(eflags), ehframe_eflags, dwarf_eflags, GENERIC_REGNUM_FLAGS,
1042      debugserver_eflags, NULL, NULL},
1043     {e_regSetGPR, gpr_eip, "eip", "pc", Uint, Hex, GPR_SIZE(eip),
1044      GPR_OFFSET(eip), ehframe_eip, dwarf_eip, GENERIC_REGNUM_PC,
1045      debugserver_eip, NULL, NULL},
1046     {e_regSetGPR, gpr_cs, "cs", NULL, Uint, Hex, GPR_SIZE(cs), GPR_OFFSET(cs),
1047      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_cs,
1048      NULL, NULL},
1049     {e_regSetGPR, gpr_ds, "ds", NULL, Uint, Hex, GPR_SIZE(ds), GPR_OFFSET(ds),
1050      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_ds,
1051      NULL, NULL},
1052     {e_regSetGPR, gpr_es, "es", NULL, Uint, Hex, GPR_SIZE(es), GPR_OFFSET(es),
1053      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_es,
1054      NULL, NULL},
1055     {e_regSetGPR, gpr_fs, "fs", NULL, Uint, Hex, GPR_SIZE(fs), GPR_OFFSET(fs),
1056      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_fs,
1057      NULL, NULL},
1058     {e_regSetGPR, gpr_gs, "gs", NULL, Uint, Hex, GPR_SIZE(gs), GPR_OFFSET(gs),
1059      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_gs,
1060      NULL, NULL},
1061     DEFINE_GPR_PSEUDO_16(ax, eax),
1062     DEFINE_GPR_PSEUDO_16(bx, ebx),
1063     DEFINE_GPR_PSEUDO_16(cx, ecx),
1064     DEFINE_GPR_PSEUDO_16(dx, edx),
1065     DEFINE_GPR_PSEUDO_16(di, edi),
1066     DEFINE_GPR_PSEUDO_16(si, esi),
1067     DEFINE_GPR_PSEUDO_16(bp, ebp),
1068     DEFINE_GPR_PSEUDO_16(sp, esp),
1069     DEFINE_GPR_PSEUDO_8H(ah, eax),
1070     DEFINE_GPR_PSEUDO_8H(bh, ebx),
1071     DEFINE_GPR_PSEUDO_8H(ch, ecx),
1072     DEFINE_GPR_PSEUDO_8H(dh, edx),
1073     DEFINE_GPR_PSEUDO_8L(al, eax),
1074     DEFINE_GPR_PSEUDO_8L(bl, ebx),
1075     DEFINE_GPR_PSEUDO_8L(cl, ecx),
1076     DEFINE_GPR_PSEUDO_8L(dl, edx),
1077     DEFINE_GPR_PSEUDO_8L(dil, edi),
1078     DEFINE_GPR_PSEUDO_8L(sil, esi),
1079     DEFINE_GPR_PSEUDO_8L(bpl, ebp),
1080     DEFINE_GPR_PSEUDO_8L(spl, esp)};
1081 
1082 const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_no_avx[] = {
1083     {e_regSetFPU, fpu_fcw, "fctrl", NULL, Uint, Hex, FPU_SIZE_UINT(fcw),
1084      FPU_OFFSET(fcw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1085      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1086     {e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw),
1087      FPU_OFFSET(fsw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1088      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1089     {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, 2 /* sizeof __fpu_ftw + sizeof __fpu_rsrv1 */,
1090      FPU_OFFSET(ftw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1091      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1092     {e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop),
1093      FPU_OFFSET(fop), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1094      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1095     {e_regSetFPU, fpu_ip, "fioff", NULL, Uint, Hex, FPU_SIZE_UINT(ip),
1096      FPU_OFFSET(ip), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1097      INVALID_NUB_REGNUM, NULL, NULL},
1098     {e_regSetFPU, fpu_cs, "fiseg", NULL, Uint, Hex, FPU_SIZE_UINT(cs),
1099      FPU_OFFSET(cs), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1100      INVALID_NUB_REGNUM, NULL, NULL},
1101     {e_regSetFPU, fpu_dp, "fooff", NULL, Uint, Hex, FPU_SIZE_UINT(dp),
1102      FPU_OFFSET(dp), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1103      INVALID_NUB_REGNUM, NULL, NULL},
1104     {e_regSetFPU, fpu_ds, "foseg", NULL, Uint, Hex, FPU_SIZE_UINT(ds),
1105      FPU_OFFSET(ds), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1106      INVALID_NUB_REGNUM, NULL, NULL},
1107     {e_regSetFPU, fpu_mxcsr, "mxcsr", NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr),
1108      FPU_OFFSET(mxcsr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1109      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1110     {e_regSetFPU, fpu_mxcsrmask, "mxcsrmask", NULL, Uint, Hex,
1111      FPU_SIZE_UINT(mxcsrmask), FPU_OFFSET(mxcsrmask), INVALID_NUB_REGNUM,
1112      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1113 
1114     {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8,
1115      FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0,
1116      INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL},
1117     {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8,
1118      FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1,
1119      INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL},
1120     {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8,
1121      FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2,
1122      INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL},
1123     {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8,
1124      FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3,
1125      INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL},
1126     {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8,
1127      FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4,
1128      INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL},
1129     {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8,
1130      FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5,
1131      INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL},
1132     {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8,
1133      FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6,
1134      INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL},
1135     {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8,
1136      FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7,
1137      INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL},
1138 
1139     {e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8,
1140      FPU_SIZE_XMM(xmm0), FPU_OFFSET(xmm0), INVALID_NUB_REGNUM, dwarf_xmm0,
1141      INVALID_NUB_REGNUM, debugserver_xmm0, NULL, NULL},
1142     {e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8,
1143      FPU_SIZE_XMM(xmm1), FPU_OFFSET(xmm1), INVALID_NUB_REGNUM, dwarf_xmm1,
1144      INVALID_NUB_REGNUM, debugserver_xmm1, NULL, NULL},
1145     {e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8,
1146      FPU_SIZE_XMM(xmm2), FPU_OFFSET(xmm2), INVALID_NUB_REGNUM, dwarf_xmm2,
1147      INVALID_NUB_REGNUM, debugserver_xmm2, NULL, NULL},
1148     {e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8,
1149      FPU_SIZE_XMM(xmm3), FPU_OFFSET(xmm3), INVALID_NUB_REGNUM, dwarf_xmm3,
1150      INVALID_NUB_REGNUM, debugserver_xmm3, NULL, NULL},
1151     {e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8,
1152      FPU_SIZE_XMM(xmm4), FPU_OFFSET(xmm4), INVALID_NUB_REGNUM, dwarf_xmm4,
1153      INVALID_NUB_REGNUM, debugserver_xmm4, NULL, NULL},
1154     {e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8,
1155      FPU_SIZE_XMM(xmm5), FPU_OFFSET(xmm5), INVALID_NUB_REGNUM, dwarf_xmm5,
1156      INVALID_NUB_REGNUM, debugserver_xmm5, NULL, NULL},
1157     {e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8,
1158      FPU_SIZE_XMM(xmm6), FPU_OFFSET(xmm6), INVALID_NUB_REGNUM, dwarf_xmm6,
1159      INVALID_NUB_REGNUM, debugserver_xmm6, NULL, NULL},
1160     {e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8,
1161      FPU_SIZE_XMM(xmm7), FPU_OFFSET(xmm7), INVALID_NUB_REGNUM, dwarf_xmm7,
1162      INVALID_NUB_REGNUM, debugserver_xmm7, NULL, NULL}};
1163 
1164 static const char *g_contained_ymm0[] = {"ymm0", NULL};
1165 static const char *g_contained_ymm1[] = {"ymm1", NULL};
1166 static const char *g_contained_ymm2[] = {"ymm2", NULL};
1167 static const char *g_contained_ymm3[] = {"ymm3", NULL};
1168 static const char *g_contained_ymm4[] = {"ymm4", NULL};
1169 static const char *g_contained_ymm5[] = {"ymm5", NULL};
1170 static const char *g_contained_ymm6[] = {"ymm6", NULL};
1171 static const char *g_contained_ymm7[] = {"ymm7", NULL};
1172 
1173 const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_avx[] = {
1174     {e_regSetFPU, fpu_fcw, "fctrl", NULL, Uint, Hex, FPU_SIZE_UINT(fcw),
1175      AVX_OFFSET(fcw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1176      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1177     {e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw),
1178      AVX_OFFSET(fsw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1179      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1180     {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, 2 /* sizeof __fpu_ftw + sizeof __fpu_rsrv1 */,
1181      AVX_OFFSET(ftw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1182      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1183     {e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop),
1184      AVX_OFFSET(fop), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1185      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1186     {e_regSetFPU, fpu_ip, "fioff", NULL, Uint, Hex, FPU_SIZE_UINT(ip),
1187      AVX_OFFSET(ip), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1188      INVALID_NUB_REGNUM, NULL, NULL},
1189     {e_regSetFPU, fpu_cs, "fiseg", NULL, Uint, Hex, FPU_SIZE_UINT(cs),
1190      AVX_OFFSET(cs), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1191      INVALID_NUB_REGNUM, NULL, NULL},
1192     {e_regSetFPU, fpu_dp, "fooff", NULL, Uint, Hex, FPU_SIZE_UINT(dp),
1193      AVX_OFFSET(dp), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1194      INVALID_NUB_REGNUM, NULL, NULL},
1195     {e_regSetFPU, fpu_ds, "foseg", NULL, Uint, Hex, FPU_SIZE_UINT(ds),
1196      AVX_OFFSET(ds), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1197      INVALID_NUB_REGNUM, NULL, NULL},
1198     {e_regSetFPU, fpu_mxcsr, "mxcsr", NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr),
1199      AVX_OFFSET(mxcsr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1200      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1201     {e_regSetFPU, fpu_mxcsrmask, "mxcsrmask", NULL, Uint, Hex,
1202      FPU_SIZE_UINT(mxcsrmask), AVX_OFFSET(mxcsrmask), INVALID_NUB_REGNUM,
1203      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1204 
1205     {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8,
1206      FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0,
1207      INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL},
1208     {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8,
1209      FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1,
1210      INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL},
1211     {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8,
1212      FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2,
1213      INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL},
1214     {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8,
1215      FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3,
1216      INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL},
1217     {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8,
1218      FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4,
1219      INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL},
1220     {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8,
1221      FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5,
1222      INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL},
1223     {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8,
1224      FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6,
1225      INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL},
1226     {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8,
1227      FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7,
1228      INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL},
1229 
1230     {e_regSetFPU, fpu_ymm0, "ymm0", NULL, Vector, VectorOfUInt8,
1231      FPU_SIZE_YMM(ymm0), AVX_OFFSET_YMM(0), INVALID_NUB_REGNUM, dwarf_ymm0,
1232      INVALID_NUB_REGNUM, debugserver_ymm0, NULL, NULL},
1233     {e_regSetFPU, fpu_ymm1, "ymm1", NULL, Vector, VectorOfUInt8,
1234      FPU_SIZE_YMM(ymm1), AVX_OFFSET_YMM(1), INVALID_NUB_REGNUM, dwarf_ymm1,
1235      INVALID_NUB_REGNUM, debugserver_ymm1, NULL, NULL},
1236     {e_regSetFPU, fpu_ymm2, "ymm2", NULL, Vector, VectorOfUInt8,
1237      FPU_SIZE_YMM(ymm2), AVX_OFFSET_YMM(2), INVALID_NUB_REGNUM, dwarf_ymm2,
1238      INVALID_NUB_REGNUM, debugserver_ymm2, NULL, NULL},
1239     {e_regSetFPU, fpu_ymm3, "ymm3", NULL, Vector, VectorOfUInt8,
1240      FPU_SIZE_YMM(ymm3), AVX_OFFSET_YMM(3), INVALID_NUB_REGNUM, dwarf_ymm3,
1241      INVALID_NUB_REGNUM, debugserver_ymm3, NULL, NULL},
1242     {e_regSetFPU, fpu_ymm4, "ymm4", NULL, Vector, VectorOfUInt8,
1243      FPU_SIZE_YMM(ymm4), AVX_OFFSET_YMM(4), INVALID_NUB_REGNUM, dwarf_ymm4,
1244      INVALID_NUB_REGNUM, debugserver_ymm4, NULL, NULL},
1245     {e_regSetFPU, fpu_ymm5, "ymm5", NULL, Vector, VectorOfUInt8,
1246      FPU_SIZE_YMM(ymm5), AVX_OFFSET_YMM(5), INVALID_NUB_REGNUM, dwarf_ymm5,
1247      INVALID_NUB_REGNUM, debugserver_ymm5, NULL, NULL},
1248     {e_regSetFPU, fpu_ymm6, "ymm6", NULL, Vector, VectorOfUInt8,
1249      FPU_SIZE_YMM(ymm6), AVX_OFFSET_YMM(6), INVALID_NUB_REGNUM, dwarf_ymm6,
1250      INVALID_NUB_REGNUM, debugserver_ymm6, NULL, NULL},
1251     {e_regSetFPU, fpu_ymm7, "ymm7", NULL, Vector, VectorOfUInt8,
1252      FPU_SIZE_YMM(ymm7), AVX_OFFSET_YMM(7), INVALID_NUB_REGNUM, dwarf_ymm7,
1253      INVALID_NUB_REGNUM, debugserver_ymm7, NULL, NULL},
1254 
1255     {e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8,
1256      FPU_SIZE_XMM(xmm0), 0, INVALID_NUB_REGNUM, dwarf_xmm0, INVALID_NUB_REGNUM,
1257      debugserver_xmm0, g_contained_ymm0, NULL},
1258     {e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8,
1259      FPU_SIZE_XMM(xmm1), 0, INVALID_NUB_REGNUM, dwarf_xmm1, INVALID_NUB_REGNUM,
1260      debugserver_xmm1, g_contained_ymm1, NULL},
1261     {e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8,
1262      FPU_SIZE_XMM(xmm2), 0, INVALID_NUB_REGNUM, dwarf_xmm2, INVALID_NUB_REGNUM,
1263      debugserver_xmm2, g_contained_ymm2, NULL},
1264     {e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8,
1265      FPU_SIZE_XMM(xmm3), 0, INVALID_NUB_REGNUM, dwarf_xmm3, INVALID_NUB_REGNUM,
1266      debugserver_xmm3, g_contained_ymm3, NULL},
1267     {e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8,
1268      FPU_SIZE_XMM(xmm4), 0, INVALID_NUB_REGNUM, dwarf_xmm4, INVALID_NUB_REGNUM,
1269      debugserver_xmm4, g_contained_ymm4, NULL},
1270     {e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8,
1271      FPU_SIZE_XMM(xmm5), 0, INVALID_NUB_REGNUM, dwarf_xmm5, INVALID_NUB_REGNUM,
1272      debugserver_xmm5, g_contained_ymm5, NULL},
1273     {e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8,
1274      FPU_SIZE_XMM(xmm6), 0, INVALID_NUB_REGNUM, dwarf_xmm6, INVALID_NUB_REGNUM,
1275      debugserver_xmm6, g_contained_ymm6, NULL},
1276     {e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8,
1277      FPU_SIZE_XMM(xmm7), 0, INVALID_NUB_REGNUM, dwarf_xmm7, INVALID_NUB_REGNUM,
1278      debugserver_xmm7, g_contained_ymm7, NULL},
1279 
1280 };
1281 
1282 const DNBRegisterInfo DNBArchImplI386::g_exc_registers[] = {
1283     {e_regSetEXC, exc_trapno, "trapno", NULL, Uint, Hex, EXC_SIZE(trapno),
1284      EXC_OFFSET(trapno), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1285      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1286     {e_regSetEXC, exc_err, "err", NULL, Uint, Hex, EXC_SIZE(err),
1287      EXC_OFFSET(err), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1288      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1289     {e_regSetEXC, exc_faultvaddr, "faultvaddr", NULL, Uint, Hex,
1290      EXC_SIZE(faultvaddr), EXC_OFFSET(faultvaddr), INVALID_NUB_REGNUM,
1291      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}};
1292 
1293 // Number of registers in each register set
1294 const size_t DNBArchImplI386::k_num_gpr_registers =
1295     sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo);
1296 const size_t DNBArchImplI386::k_num_fpu_registers_no_avx =
1297     sizeof(g_fpu_registers_no_avx) / sizeof(DNBRegisterInfo);
1298 const size_t DNBArchImplI386::k_num_fpu_registers_avx =
1299     sizeof(g_fpu_registers_avx) / sizeof(DNBRegisterInfo);
1300 const size_t DNBArchImplI386::k_num_exc_registers =
1301     sizeof(g_exc_registers) / sizeof(DNBRegisterInfo);
1302 const size_t DNBArchImplI386::k_num_all_registers_no_avx =
1303     k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers;
1304 const size_t DNBArchImplI386::k_num_all_registers_avx =
1305     k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers;
1306 
1307 //----------------------------------------------------------------------
1308 // Register set definitions. The first definitions at register set index
1309 // of zero is for all registers, followed by other registers sets. The
1310 // register information for the all register set need not be filled in.
1311 //----------------------------------------------------------------------
1312 const DNBRegisterSetInfo DNBArchImplI386::g_reg_sets_no_avx[] = {
1313     {"i386 Registers", NULL, k_num_all_registers_no_avx},
1314     {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers},
1315     {"Floating Point Registers", g_fpu_registers_no_avx,
1316      k_num_fpu_registers_no_avx},
1317     {"Exception State Registers", g_exc_registers, k_num_exc_registers}};
1318 
1319 const DNBRegisterSetInfo DNBArchImplI386::g_reg_sets_avx[] = {
1320     {"i386 Registers", NULL, k_num_all_registers_avx},
1321     {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers},
1322     {"Floating Point Registers", g_fpu_registers_avx, k_num_fpu_registers_avx},
1323     {"Exception State Registers", g_exc_registers, k_num_exc_registers}};
1324 
1325 // Total number of register sets for this architecture
1326 const size_t DNBArchImplI386::k_num_register_sets =
1327     sizeof(g_reg_sets_no_avx) / sizeof(DNBRegisterSetInfo);
1328 
1329 DNBArchProtocol *DNBArchImplI386::Create(MachThread *thread) {
1330   DNBArchImplI386 *obj = new DNBArchImplI386(thread);
1331   return obj;
1332 }
1333 
1334 const uint8_t *DNBArchImplI386::SoftwareBreakpointOpcode(nub_size_t byte_size) {
1335   static const uint8_t g_breakpoint_opcode[] = {0xCC};
1336   if (byte_size == 1)
1337     return g_breakpoint_opcode;
1338   return NULL;
1339 }
1340 
1341 const DNBRegisterSetInfo *
1342 DNBArchImplI386::GetRegisterSetInfo(nub_size_t *num_reg_sets) {
1343   *num_reg_sets = k_num_register_sets;
1344   if (CPUHasAVX() || FORCE_AVX_REGS)
1345     return g_reg_sets_avx;
1346   else
1347     return g_reg_sets_no_avx;
1348 }
1349 
1350 void DNBArchImplI386::Initialize() {
1351   DNBArchPluginInfo arch_plugin_info = {
1352       CPU_TYPE_I386, DNBArchImplI386::Create,
1353       DNBArchImplI386::GetRegisterSetInfo,
1354       DNBArchImplI386::SoftwareBreakpointOpcode};
1355 
1356   // Register this arch plug-in with the main protocol class
1357   DNBArchProtocol::RegisterArchPlugin(arch_plugin_info);
1358 }
1359 
1360 bool DNBArchImplI386::GetRegisterValue(uint32_t set, uint32_t reg,
1361                                        DNBRegisterValue *value) {
1362   if (set == REGISTER_SET_GENERIC) {
1363     switch (reg) {
1364     case GENERIC_REGNUM_PC: // Program Counter
1365       set = e_regSetGPR;
1366       reg = gpr_eip;
1367       break;
1368 
1369     case GENERIC_REGNUM_SP: // Stack Pointer
1370       set = e_regSetGPR;
1371       reg = gpr_esp;
1372       break;
1373 
1374     case GENERIC_REGNUM_FP: // Frame Pointer
1375       set = e_regSetGPR;
1376       reg = gpr_ebp;
1377       break;
1378 
1379     case GENERIC_REGNUM_FLAGS: // Processor flags register
1380       set = e_regSetGPR;
1381       reg = gpr_eflags;
1382       break;
1383 
1384     case GENERIC_REGNUM_RA: // Return Address
1385     default:
1386       return false;
1387     }
1388   }
1389 
1390   if (GetRegisterState(set, false) != KERN_SUCCESS)
1391     return false;
1392 
1393   const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
1394   if (regInfo) {
1395     value->info = *regInfo;
1396     switch (set) {
1397     case e_regSetGPR:
1398       if (reg < k_num_gpr_registers) {
1399         value->value.uint32 = ((uint32_t *)(&m_state.context.gpr))[reg];
1400         return true;
1401       }
1402       break;
1403 
1404     case e_regSetFPU:
1405       if (reg > fpu_xmm7 && !(CPUHasAVX() || FORCE_AVX_REGS))
1406         return false;
1407       switch (reg) {
1408       case fpu_fcw:
1409         value->value.uint16 =
1410             *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw));
1411         return true;
1412       case fpu_fsw:
1413         value->value.uint16 =
1414             *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw));
1415         return true;
1416       case fpu_ftw:
1417         memcpy (&value->value.uint16, &m_state.context.fpu.no_avx.__fpu_ftw, 2);
1418         return true;
1419       case fpu_fop:
1420         value->value.uint16 = m_state.context.fpu.no_avx.__fpu_fop;
1421         return true;
1422       case fpu_ip:
1423         value->value.uint32 = m_state.context.fpu.no_avx.__fpu_ip;
1424         return true;
1425       case fpu_cs:
1426         value->value.uint16 = m_state.context.fpu.no_avx.__fpu_cs;
1427         return true;
1428       case fpu_dp:
1429         value->value.uint32 = m_state.context.fpu.no_avx.__fpu_dp;
1430         return true;
1431       case fpu_ds:
1432         value->value.uint16 = m_state.context.fpu.no_avx.__fpu_ds;
1433         return true;
1434       case fpu_mxcsr:
1435         value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsr;
1436         return true;
1437       case fpu_mxcsrmask:
1438         value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsrmask;
1439         return true;
1440 
1441       case fpu_stmm0:
1442         memcpy(&value->value.uint8,
1443                m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg, 10);
1444         return true;
1445       case fpu_stmm1:
1446         memcpy(&value->value.uint8,
1447                m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg, 10);
1448         return true;
1449       case fpu_stmm2:
1450         memcpy(&value->value.uint8,
1451                m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg, 10);
1452         return true;
1453       case fpu_stmm3:
1454         memcpy(&value->value.uint8,
1455                m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg, 10);
1456         return true;
1457       case fpu_stmm4:
1458         memcpy(&value->value.uint8,
1459                m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg, 10);
1460         return true;
1461       case fpu_stmm5:
1462         memcpy(&value->value.uint8,
1463                m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg, 10);
1464         return true;
1465       case fpu_stmm6:
1466         memcpy(&value->value.uint8,
1467                m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg, 10);
1468         return true;
1469       case fpu_stmm7:
1470         memcpy(&value->value.uint8,
1471                m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg, 10);
1472         return true;
1473 
1474       case fpu_xmm0:
1475         memcpy(&value->value.uint8,
1476                m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg, 16);
1477         return true;
1478       case fpu_xmm1:
1479         memcpy(&value->value.uint8,
1480                m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg, 16);
1481         return true;
1482       case fpu_xmm2:
1483         memcpy(&value->value.uint8,
1484                m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg, 16);
1485         return true;
1486       case fpu_xmm3:
1487         memcpy(&value->value.uint8,
1488                m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg, 16);
1489         return true;
1490       case fpu_xmm4:
1491         memcpy(&value->value.uint8,
1492                m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg, 16);
1493         return true;
1494       case fpu_xmm5:
1495         memcpy(&value->value.uint8,
1496                m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg, 16);
1497         return true;
1498       case fpu_xmm6:
1499         memcpy(&value->value.uint8,
1500                m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg, 16);
1501         return true;
1502       case fpu_xmm7:
1503         memcpy(&value->value.uint8,
1504                m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg, 16);
1505         return true;
1506 
1507 #define MEMCPY_YMM(n)                                                          \
1508   memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm##n.__xmm_reg,  \
1509          16);                                                                  \
1510   memcpy((&value->value.uint8) + 16,                                           \
1511          m_state.context.fpu.avx.__fpu_ymmh##n.__xmm_reg, 16);
1512       case fpu_ymm0:
1513         MEMCPY_YMM(0);
1514         return true;
1515       case fpu_ymm1:
1516         MEMCPY_YMM(1);
1517         return true;
1518       case fpu_ymm2:
1519         MEMCPY_YMM(2);
1520         return true;
1521       case fpu_ymm3:
1522         MEMCPY_YMM(3);
1523         return true;
1524       case fpu_ymm4:
1525         MEMCPY_YMM(4);
1526         return true;
1527       case fpu_ymm5:
1528         MEMCPY_YMM(5);
1529         return true;
1530       case fpu_ymm6:
1531         MEMCPY_YMM(6);
1532         return true;
1533       case fpu_ymm7:
1534         MEMCPY_YMM(7);
1535         return true;
1536 #undef MEMCPY_YMM
1537       }
1538       break;
1539 
1540     case e_regSetEXC:
1541       if (reg < k_num_exc_registers) {
1542         value->value.uint32 = (&m_state.context.exc.__trapno)[reg];
1543         return true;
1544       }
1545       break;
1546     }
1547   }
1548   return false;
1549 }
1550 
1551 bool DNBArchImplI386::SetRegisterValue(uint32_t set, uint32_t reg,
1552                                        const DNBRegisterValue *value) {
1553   if (set == REGISTER_SET_GENERIC) {
1554     switch (reg) {
1555     case GENERIC_REGNUM_PC: // Program Counter
1556       set = e_regSetGPR;
1557       reg = gpr_eip;
1558       break;
1559 
1560     case GENERIC_REGNUM_SP: // Stack Pointer
1561       set = e_regSetGPR;
1562       reg = gpr_esp;
1563       break;
1564 
1565     case GENERIC_REGNUM_FP: // Frame Pointer
1566       set = e_regSetGPR;
1567       reg = gpr_ebp;
1568       break;
1569 
1570     case GENERIC_REGNUM_FLAGS: // Processor flags register
1571       set = e_regSetGPR;
1572       reg = gpr_eflags;
1573       break;
1574 
1575     case GENERIC_REGNUM_RA: // Return Address
1576     default:
1577       return false;
1578     }
1579   }
1580 
1581   if (GetRegisterState(set, false) != KERN_SUCCESS)
1582     return false;
1583 
1584   bool success = false;
1585   const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
1586   if (regInfo) {
1587     switch (set) {
1588     case e_regSetGPR:
1589       if (reg < k_num_gpr_registers) {
1590         ((uint32_t *)(&m_state.context.gpr))[reg] = value->value.uint32;
1591         success = true;
1592       }
1593       break;
1594 
1595     case e_regSetFPU:
1596       if (reg > fpu_xmm7 && !(CPUHasAVX() || FORCE_AVX_REGS))
1597         return false;
1598       switch (reg) {
1599       case fpu_fcw:
1600         *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)) =
1601             value->value.uint16;
1602         success = true;
1603         break;
1604       case fpu_fsw:
1605         *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)) =
1606             value->value.uint16;
1607         success = true;
1608         break;
1609       case fpu_ftw:
1610         memcpy (&m_state.context.fpu.no_avx.__fpu_ftw, &value->value.uint16, 2);
1611         success = true;
1612         break;
1613       case fpu_fop:
1614         m_state.context.fpu.no_avx.__fpu_fop = value->value.uint16;
1615         success = true;
1616         break;
1617       case fpu_ip:
1618         m_state.context.fpu.no_avx.__fpu_ip = value->value.uint32;
1619         success = true;
1620         break;
1621       case fpu_cs:
1622         m_state.context.fpu.no_avx.__fpu_cs = value->value.uint16;
1623         success = true;
1624         break;
1625       case fpu_dp:
1626         m_state.context.fpu.no_avx.__fpu_dp = value->value.uint32;
1627         success = true;
1628         break;
1629       case fpu_ds:
1630         m_state.context.fpu.no_avx.__fpu_ds = value->value.uint16;
1631         success = true;
1632         break;
1633       case fpu_mxcsr:
1634         m_state.context.fpu.no_avx.__fpu_mxcsr = value->value.uint32;
1635         success = true;
1636         break;
1637       case fpu_mxcsrmask:
1638         m_state.context.fpu.no_avx.__fpu_mxcsrmask = value->value.uint32;
1639         success = true;
1640         break;
1641 
1642       case fpu_stmm0:
1643         memcpy(m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg,
1644                &value->value.uint8, 10);
1645         success = true;
1646         break;
1647       case fpu_stmm1:
1648         memcpy(m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg,
1649                &value->value.uint8, 10);
1650         success = true;
1651         break;
1652       case fpu_stmm2:
1653         memcpy(m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg,
1654                &value->value.uint8, 10);
1655         success = true;
1656         break;
1657       case fpu_stmm3:
1658         memcpy(m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg,
1659                &value->value.uint8, 10);
1660         success = true;
1661         break;
1662       case fpu_stmm4:
1663         memcpy(m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg,
1664                &value->value.uint8, 10);
1665         success = true;
1666         break;
1667       case fpu_stmm5:
1668         memcpy(m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg,
1669                &value->value.uint8, 10);
1670         success = true;
1671         break;
1672       case fpu_stmm6:
1673         memcpy(m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg,
1674                &value->value.uint8, 10);
1675         success = true;
1676         break;
1677       case fpu_stmm7:
1678         memcpy(m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg,
1679                &value->value.uint8, 10);
1680         success = true;
1681         break;
1682 
1683       case fpu_xmm0:
1684         memcpy(m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg,
1685                &value->value.uint8, 16);
1686         success = true;
1687         break;
1688       case fpu_xmm1:
1689         memcpy(m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg,
1690                &value->value.uint8, 16);
1691         success = true;
1692         break;
1693       case fpu_xmm2:
1694         memcpy(m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg,
1695                &value->value.uint8, 16);
1696         success = true;
1697         break;
1698       case fpu_xmm3:
1699         memcpy(m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg,
1700                &value->value.uint8, 16);
1701         success = true;
1702         break;
1703       case fpu_xmm4:
1704         memcpy(m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg,
1705                &value->value.uint8, 16);
1706         success = true;
1707         break;
1708       case fpu_xmm5:
1709         memcpy(m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg,
1710                &value->value.uint8, 16);
1711         success = true;
1712         break;
1713       case fpu_xmm6:
1714         memcpy(m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg,
1715                &value->value.uint8, 16);
1716         success = true;
1717         break;
1718       case fpu_xmm7:
1719         memcpy(m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg,
1720                &value->value.uint8, 16);
1721         success = true;
1722         break;
1723 
1724 #define MEMCPY_YMM(n)                                                          \
1725   memcpy(m_state.context.fpu.avx.__fpu_xmm##n.__xmm_reg, &value->value.uint8,  \
1726          16);                                                                  \
1727   memcpy(m_state.context.fpu.avx.__fpu_ymmh##n.__xmm_reg,                      \
1728          (&value->value.uint8) + 16, 16);
1729       case fpu_ymm0:
1730         MEMCPY_YMM(0);
1731         return true;
1732       case fpu_ymm1:
1733         MEMCPY_YMM(1);
1734         return true;
1735       case fpu_ymm2:
1736         MEMCPY_YMM(2);
1737         return true;
1738       case fpu_ymm3:
1739         MEMCPY_YMM(3);
1740         return true;
1741       case fpu_ymm4:
1742         MEMCPY_YMM(4);
1743         return true;
1744       case fpu_ymm5:
1745         MEMCPY_YMM(5);
1746         return true;
1747       case fpu_ymm6:
1748         MEMCPY_YMM(6);
1749         return true;
1750       case fpu_ymm7:
1751         MEMCPY_YMM(7);
1752         return true;
1753 #undef MEMCPY_YMM
1754       }
1755       break;
1756 
1757     case e_regSetEXC:
1758       if (reg < k_num_exc_registers) {
1759         (&m_state.context.exc.__trapno)[reg] = value->value.uint32;
1760         success = true;
1761       }
1762       break;
1763     }
1764   }
1765 
1766   if (success)
1767     return SetRegisterState(set) == KERN_SUCCESS;
1768   return false;
1769 }
1770 
1771 uint32_t DNBArchImplI386::GetRegisterContextSize() {
1772   static uint32_t g_cached_size = 0;
1773   if (g_cached_size == 0) {
1774     if (CPUHasAVX() || FORCE_AVX_REGS) {
1775       for (size_t i = 0; i < k_num_fpu_registers_avx; ++i) {
1776         if (g_fpu_registers_avx[i].value_regs == NULL)
1777           g_cached_size += g_fpu_registers_avx[i].size;
1778       }
1779     } else {
1780       for (size_t i = 0; i < k_num_fpu_registers_no_avx; ++i) {
1781         if (g_fpu_registers_no_avx[i].value_regs == NULL)
1782           g_cached_size += g_fpu_registers_no_avx[i].size;
1783       }
1784     }
1785     DNBLogThreaded("DNBArchImplX86_64::GetRegisterContextSize() - GPR = %zu, "
1786                    "FPU = %u, EXC = %zu",
1787                    sizeof(GPR), g_cached_size, sizeof(EXC));
1788     g_cached_size += sizeof(GPR);
1789     g_cached_size += sizeof(EXC);
1790     DNBLogThreaded(
1791         "DNBArchImplX86_64::GetRegisterContextSize() - GPR + FPU + EXC = %u",
1792         g_cached_size);
1793   }
1794   return g_cached_size;
1795 }
1796 
1797 nub_size_t DNBArchImplI386::GetRegisterContext(void *buf, nub_size_t buf_len) {
1798   uint32_t size = GetRegisterContextSize();
1799 
1800   if (buf && buf_len) {
1801     if (size > buf_len)
1802       size = static_cast<uint32_t>(buf_len);
1803 
1804     bool force = false;
1805     kern_return_t kret;
1806     if ((kret = GetGPRState(force)) != KERN_SUCCESS) {
1807       DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = "
1808                                    "%p, len = %llu) error: GPR regs failed to "
1809                                    "read: %u ",
1810                        buf, (uint64_t)buf_len, kret);
1811       size = 0;
1812     } else if ((kret = GetFPUState(force)) != KERN_SUCCESS) {
1813       DNBLogThreadedIf(
1814           LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = %p, len = "
1815                       "%llu) error: %s regs failed to read: %u",
1816           buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret);
1817       size = 0;
1818     } else if ((kret = GetEXCState(force)) != KERN_SUCCESS) {
1819       DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = "
1820                                    "%p, len = %llu) error: EXC regs failed to "
1821                                    "read: %u",
1822                        buf, (uint64_t)buf_len, kret);
1823       size = 0;
1824     } else {
1825       uint8_t *p = (uint8_t *)buf;
1826       // Copy the GPR registers
1827       memcpy(p, &m_state.context.gpr, sizeof(GPR));
1828       p += sizeof(GPR);
1829 
1830       // Walk around the gaps in the FPU regs
1831       memcpy(p, &m_state.context.fpu.no_avx.__fpu_fcw, 5);
1832       p += 5;
1833       memcpy(p, &m_state.context.fpu.no_avx.__fpu_fop, 8);
1834       p += 8;
1835       memcpy(p, &m_state.context.fpu.no_avx.__fpu_dp, 6);
1836       p += 6;
1837       memcpy(p, &m_state.context.fpu.no_avx.__fpu_mxcsr, 8);
1838       p += 8;
1839 
1840       // Work around the padding between the stmm registers as they are 16
1841       // byte structs with 10 bytes of the value in each
1842       for (size_t i = 0; i < 8; ++i) {
1843         memcpy(p, &m_state.context.fpu.no_avx.__fpu_stmm0 + i, 10);
1844         p += 10;
1845       }
1846 
1847       if (CPUHasAVX() || FORCE_AVX_REGS) {
1848         // Interleave the XMM and YMMH registers to make the YMM registers
1849         for (size_t i = 0; i < 8; ++i) {
1850           memcpy(p, &m_state.context.fpu.avx.__fpu_xmm0 + i, 16);
1851           p += 16;
1852           memcpy(p, &m_state.context.fpu.avx.__fpu_ymmh0 + i, 16);
1853           p += 16;
1854         }
1855       } else {
1856         // Copy the XMM registers in a single block
1857         memcpy(p, &m_state.context.fpu.no_avx.__fpu_xmm0, 8 * 16);
1858         p += 8 * 16;
1859       }
1860 
1861       // Copy the exception registers
1862       memcpy(p, &m_state.context.exc, sizeof(EXC));
1863       p += sizeof(EXC);
1864 
1865       // make sure we end up with exactly what we think we should have
1866       size_t bytes_written = p - (uint8_t *)buf;
1867       UNUSED_IF_ASSERT_DISABLED(bytes_written);
1868       assert(bytes_written == size);
1869     }
1870   }
1871   DNBLogThreadedIf(
1872       LOG_THREAD,
1873       "DNBArchImplI386::GetRegisterContext (buf = %p, len = %llu) => %llu", buf,
1874       (uint64_t)buf_len, (uint64_t)size);
1875   // Return the size of the register context even if NULL was passed in
1876   return size;
1877 }
1878 
1879 nub_size_t DNBArchImplI386::SetRegisterContext(const void *buf,
1880                                                nub_size_t buf_len) {
1881   nub_size_t size = sizeof(m_state.context);
1882   if (buf == NULL || buf_len == 0)
1883     size = 0;
1884 
1885   if (size) {
1886     if (size > buf_len)
1887       size = buf_len;
1888 
1889     uint8_t *p = (uint8_t *)buf;
1890     // Copy the GPR registers
1891     memcpy(&m_state.context.gpr, p, sizeof(GPR));
1892     p += sizeof(GPR);
1893 
1894     // Copy fcw through mxcsrmask as there is no padding
1895     memcpy(&m_state.context.fpu.no_avx.__fpu_fcw, p, 5);
1896     p += 5;
1897     memcpy(&m_state.context.fpu.no_avx.__fpu_fop, p, 8);
1898     p += 8;
1899     memcpy(&m_state.context.fpu.no_avx.__fpu_dp, p, 6);
1900     p += 6;
1901     memcpy(&m_state.context.fpu.no_avx.__fpu_mxcsr, p, 8);
1902     p += 8;
1903 
1904     // Work around the padding between the stmm registers as they are 16
1905     // byte structs with 10 bytes of the value in each
1906     for (size_t i = 0; i < 8; ++i) {
1907       memcpy(&m_state.context.fpu.no_avx.__fpu_stmm0 + i, p, 10);
1908       p += 10;
1909     }
1910 
1911     if (CPUHasAVX() || FORCE_AVX_REGS) {
1912       // Interleave the XMM and YMMH registers to make the YMM registers
1913       for (size_t i = 0; i < 8; ++i) {
1914         memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + i, p, 16);
1915         p += 16;
1916         memcpy(&m_state.context.fpu.avx.__fpu_ymmh0 + i, p, 16);
1917         p += 16;
1918       }
1919     } else {
1920       // Copy the XMM registers in a single block
1921       memcpy(&m_state.context.fpu.no_avx.__fpu_xmm0, p, 8 * 16);
1922       p += 8 * 16;
1923     }
1924 
1925     // Copy the exception registers
1926     memcpy(&m_state.context.exc, p, sizeof(EXC));
1927     p += sizeof(EXC);
1928 
1929     // make sure we end up with exactly what we think we should have
1930     size_t bytes_written = p - (uint8_t *)buf;
1931     UNUSED_IF_ASSERT_DISABLED(bytes_written);
1932     assert(bytes_written == size);
1933     kern_return_t kret;
1934     if ((kret = SetGPRState()) != KERN_SUCCESS)
1935       DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = "
1936                                    "%p, len = %llu) error: GPR regs failed to "
1937                                    "write: %u",
1938                        buf, (uint64_t)buf_len, kret);
1939     if ((kret = SetFPUState()) != KERN_SUCCESS)
1940       DNBLogThreadedIf(
1941           LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = %p, len = "
1942                       "%llu) error: %s regs failed to write: %u",
1943           buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret);
1944     if ((kret = SetEXCState()) != KERN_SUCCESS)
1945       DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = "
1946                                    "%p, len = %llu) error: EXP regs failed to "
1947                                    "write: %u",
1948                        buf, (uint64_t)buf_len, kret);
1949   }
1950   DNBLogThreadedIf(
1951       LOG_THREAD,
1952       "DNBArchImplI386::SetRegisterContext (buf = %p, len = %llu) => %llu", buf,
1953       (uint64_t)buf_len, (uint64_t)size);
1954   return size;
1955 }
1956 
1957 uint32_t DNBArchImplI386::SaveRegisterState() {
1958   kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
1959   DNBLogThreadedIf(
1960       LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u "
1961                   "(SetGPRState() for stop_count = %u)",
1962       m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
1963 
1964   bool force = true;
1965 
1966   if ((kret = GetGPRState(force)) != KERN_SUCCESS) {
1967     DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: "
1968                                  "GPR regs failed to read: %u ",
1969                      kret);
1970   } else if ((kret = GetFPUState(force)) != KERN_SUCCESS) {
1971     DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: "
1972                                  "%s regs failed to read: %u",
1973                      CPUHasAVX() ? "AVX" : "FPU", kret);
1974   } else {
1975     const uint32_t save_id = GetNextRegisterStateSaveID();
1976     m_saved_register_states[save_id] = m_state.context;
1977     return save_id;
1978   }
1979   return 0;
1980 }
1981 bool DNBArchImplI386::RestoreRegisterState(uint32_t save_id) {
1982   SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id);
1983   if (pos != m_saved_register_states.end()) {
1984     m_state.context.gpr = pos->second.gpr;
1985     m_state.context.fpu = pos->second.fpu;
1986     m_state.context.exc = pos->second.exc;
1987     m_state.SetError(e_regSetGPR, Read, 0);
1988     m_state.SetError(e_regSetFPU, Read, 0);
1989     m_state.SetError(e_regSetEXC, Read, 0);
1990     kern_return_t kret;
1991     bool success = true;
1992     if ((kret = SetGPRState()) != KERN_SUCCESS) {
1993       DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::RestoreRegisterState "
1994                                    "(save_id = %u) error: GPR regs failed to "
1995                                    "write: %u",
1996                        save_id, kret);
1997       success = false;
1998     } else if ((kret = SetFPUState()) != KERN_SUCCESS) {
1999       DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::RestoreRegisterState "
2000                                    "(save_id = %u) error: %s regs failed to "
2001                                    "write: %u",
2002                        save_id, CPUHasAVX() ? "AVX" : "FPU", kret);
2003       success = false;
2004     }
2005     m_saved_register_states.erase(pos);
2006     return success;
2007   }
2008   return false;
2009 }
2010 
2011 kern_return_t DNBArchImplI386::GetRegisterState(int set, bool force) {
2012   switch (set) {
2013   case e_regSetALL:
2014     return GetGPRState(force) | GetFPUState(force) | GetEXCState(force);
2015   case e_regSetGPR:
2016     return GetGPRState(force);
2017   case e_regSetFPU:
2018     return GetFPUState(force);
2019   case e_regSetEXC:
2020     return GetEXCState(force);
2021   default:
2022     break;
2023   }
2024   return KERN_INVALID_ARGUMENT;
2025 }
2026 
2027 kern_return_t DNBArchImplI386::SetRegisterState(int set) {
2028   // Make sure we have a valid context to set.
2029   if (RegisterSetStateIsValid(set)) {
2030     switch (set) {
2031     case e_regSetALL:
2032       return SetGPRState() | SetFPUState() | SetEXCState();
2033     case e_regSetGPR:
2034       return SetGPRState();
2035     case e_regSetFPU:
2036       return SetFPUState();
2037     case e_regSetEXC:
2038       return SetEXCState();
2039     default:
2040       break;
2041     }
2042   }
2043   return KERN_INVALID_ARGUMENT;
2044 }
2045 
2046 bool DNBArchImplI386::RegisterSetStateIsValid(int set) const {
2047   return m_state.RegsAreValid(set);
2048 }
2049 
2050 #endif // #if defined (__i386__)
2051