1 //===-- RegisterContextDarwin_i386.cpp ------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/DataBufferHeap.h"
10 #include "lldb/Utility/DataExtractor.h"
11 #include "lldb/Utility/Endian.h"
12 #include "lldb/Utility/Log.h"
13 #include "lldb/Utility/RegisterValue.h"
14 #include "lldb/Utility/Scalar.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/Support/Compiler.h"
22 #include "RegisterContextDarwin_i386.h"
25 using namespace lldb_private
;
130 #define GPR_OFFSET(reg) \
131 (LLVM_EXTENSION offsetof(RegisterContextDarwin_i386::GPR, reg))
132 #define FPU_OFFSET(reg) \
133 (LLVM_EXTENSION offsetof(RegisterContextDarwin_i386::FPU, reg) + \
134 sizeof(RegisterContextDarwin_i386::GPR))
135 #define EXC_OFFSET(reg) \
136 (LLVM_EXTENSION offsetof(RegisterContextDarwin_i386::EXC, reg) + \
137 sizeof(RegisterContextDarwin_i386::GPR) + \
138 sizeof(RegisterContextDarwin_i386::FPU))
140 // These macros will auto define the register name, alt name, register size,
141 // register offset, encoding, format and native register. This ensures that the
142 // register state structures are defined correctly and have the correct sizes
144 #define DEFINE_GPR(reg, alt) \
145 #reg, alt, sizeof(((RegisterContextDarwin_i386::GPR *) NULL)->reg), \
146 GPR_OFFSET(reg), eEncodingUint, eFormatHex
147 #define DEFINE_FPU_UINT(reg) \
148 #reg, NULL, sizeof(((RegisterContextDarwin_i386::FPU *) NULL)->reg), \
149 FPU_OFFSET(reg), eEncodingUint, eFormatHex
150 #define DEFINE_FPU_VECT(reg, i) \
152 sizeof(((RegisterContextDarwin_i386::FPU *) NULL)->reg[i].bytes), \
153 FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, \
154 {LLDB_INVALID_REGNUM, dwarf_##reg##i, \
155 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
157 nullptr, nullptr, nullptr,
159 #define DEFINE_EXC(reg) \
160 #reg, NULL, sizeof(((RegisterContextDarwin_i386::EXC *) NULL)->reg), \
161 EXC_OFFSET(reg), eEncodingUint, eFormatHex
162 #define REG_CONTEXT_SIZE \
163 (sizeof(RegisterContextDarwin_i386::GPR) + \
164 sizeof(RegisterContextDarwin_i386::FPU) + \
165 sizeof(RegisterContextDarwin_i386::EXC))
167 static RegisterInfo g_register_infos
[] = {
168 {DEFINE_GPR(eax
, nullptr),
169 {ehframe_eax
, dwarf_eax
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
175 {DEFINE_GPR(ebx
, nullptr),
176 {ehframe_ebx
, dwarf_ebx
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
182 {DEFINE_GPR(ecx
, nullptr),
183 {ehframe_ecx
, dwarf_ecx
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
189 {DEFINE_GPR(edx
, nullptr),
190 {ehframe_edx
, dwarf_edx
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
196 {DEFINE_GPR(edi
, nullptr),
197 {ehframe_edi
, dwarf_edi
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
203 {DEFINE_GPR(esi
, nullptr),
204 {ehframe_esi
, dwarf_esi
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
210 {DEFINE_GPR(ebp
, "fp"),
211 {ehframe_ebp
, dwarf_ebp
, LLDB_REGNUM_GENERIC_FP
, LLDB_INVALID_REGNUM
,
217 {DEFINE_GPR(esp
, "sp"),
218 {ehframe_esp
, dwarf_esp
, LLDB_REGNUM_GENERIC_SP
, LLDB_INVALID_REGNUM
,
224 {DEFINE_GPR(ss
, nullptr),
225 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
226 LLDB_INVALID_REGNUM
, gpr_ss
},
231 {DEFINE_GPR(eflags
, "flags"),
232 {ehframe_eflags
, dwarf_eflags
, LLDB_REGNUM_GENERIC_FLAGS
,
233 LLDB_INVALID_REGNUM
, gpr_eflags
},
238 {DEFINE_GPR(eip
, "pc"),
239 {ehframe_eip
, dwarf_eip
, LLDB_REGNUM_GENERIC_PC
, LLDB_INVALID_REGNUM
,
245 {DEFINE_GPR(cs
, nullptr),
246 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
247 LLDB_INVALID_REGNUM
, gpr_cs
},
252 {DEFINE_GPR(ds
, nullptr),
253 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
254 LLDB_INVALID_REGNUM
, gpr_ds
},
259 {DEFINE_GPR(es
, nullptr),
260 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
261 LLDB_INVALID_REGNUM
, gpr_es
},
266 {DEFINE_GPR(fs
, nullptr),
267 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
268 LLDB_INVALID_REGNUM
, gpr_fs
},
273 {DEFINE_GPR(gs
, nullptr),
274 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
275 LLDB_INVALID_REGNUM
, gpr_gs
},
281 {DEFINE_FPU_UINT(fcw
),
282 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
283 LLDB_INVALID_REGNUM
, fpu_fcw
},
288 {DEFINE_FPU_UINT(fsw
),
289 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
290 LLDB_INVALID_REGNUM
, fpu_fsw
},
295 {DEFINE_FPU_UINT(ftw
),
296 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
297 LLDB_INVALID_REGNUM
, fpu_ftw
},
302 {DEFINE_FPU_UINT(fop
),
303 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
304 LLDB_INVALID_REGNUM
, fpu_fop
},
309 {DEFINE_FPU_UINT(ip
),
310 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
311 LLDB_INVALID_REGNUM
, fpu_ip
},
316 {DEFINE_FPU_UINT(cs
),
317 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
318 LLDB_INVALID_REGNUM
, fpu_cs
},
323 {DEFINE_FPU_UINT(dp
),
324 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
325 LLDB_INVALID_REGNUM
, fpu_dp
},
330 {DEFINE_FPU_UINT(ds
),
331 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
332 LLDB_INVALID_REGNUM
, fpu_ds
},
337 {DEFINE_FPU_UINT(mxcsr
),
338 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
339 LLDB_INVALID_REGNUM
, fpu_mxcsr
},
344 {DEFINE_FPU_UINT(mxcsrmask
),
345 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
346 LLDB_INVALID_REGNUM
, fpu_mxcsrmask
},
351 {DEFINE_FPU_VECT(stmm
, 0)},
352 {DEFINE_FPU_VECT(stmm
, 1)},
353 {DEFINE_FPU_VECT(stmm
, 2)},
354 {DEFINE_FPU_VECT(stmm
, 3)},
355 {DEFINE_FPU_VECT(stmm
, 4)},
356 {DEFINE_FPU_VECT(stmm
, 5)},
357 {DEFINE_FPU_VECT(stmm
, 6)},
358 {DEFINE_FPU_VECT(stmm
, 7)},
359 {DEFINE_FPU_VECT(xmm
, 0)},
360 {DEFINE_FPU_VECT(xmm
, 1)},
361 {DEFINE_FPU_VECT(xmm
, 2)},
362 {DEFINE_FPU_VECT(xmm
, 3)},
363 {DEFINE_FPU_VECT(xmm
, 4)},
364 {DEFINE_FPU_VECT(xmm
, 5)},
365 {DEFINE_FPU_VECT(xmm
, 6)},
366 {DEFINE_FPU_VECT(xmm
, 7)},
369 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
370 LLDB_INVALID_REGNUM
, exc_trapno
},
376 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
377 LLDB_INVALID_REGNUM
, exc_err
},
382 {DEFINE_EXC(faultvaddr
),
383 {LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
, LLDB_INVALID_REGNUM
,
384 LLDB_INVALID_REGNUM
, exc_faultvaddr
},
390 static size_t k_num_register_infos
= std::size(g_register_infos
);
392 RegisterContextDarwin_i386::RegisterContextDarwin_i386(
393 Thread
&thread
, uint32_t concrete_frame_idx
)
394 : RegisterContext(thread
, concrete_frame_idx
), gpr(), fpu(), exc() {
396 for (i
= 0; i
< kNumErrors
; i
++) {
403 RegisterContextDarwin_i386::~RegisterContextDarwin_i386() = default;
405 void RegisterContextDarwin_i386::InvalidateAllRegisters() {
406 InvalidateAllRegisterStates();
409 size_t RegisterContextDarwin_i386::GetRegisterCount() {
410 assert(k_num_register_infos
== k_num_registers
);
411 return k_num_registers
;
415 RegisterContextDarwin_i386::GetRegisterInfoAtIndex(size_t reg
) {
416 assert(k_num_register_infos
== k_num_registers
);
417 if (reg
< k_num_registers
)
418 return &g_register_infos
[reg
];
422 size_t RegisterContextDarwin_i386::GetRegisterInfosCount() {
423 return k_num_register_infos
;
426 const RegisterInfo
*RegisterContextDarwin_i386::GetRegisterInfos() {
427 return g_register_infos
;
430 // General purpose registers
431 static uint32_t g_gpr_regnums
[] = {
432 gpr_eax
, gpr_ebx
, gpr_ecx
, gpr_edx
, gpr_edi
, gpr_esi
, gpr_ebp
, gpr_esp
,
433 gpr_ss
, gpr_eflags
, gpr_eip
, gpr_cs
, gpr_ds
, gpr_es
, gpr_fs
, gpr_gs
};
435 // Floating point registers
436 static uint32_t g_fpu_regnums
[] = {
437 fpu_fcw
, fpu_fsw
, fpu_ftw
, fpu_fop
, fpu_ip
, fpu_cs
,
438 fpu_dp
, fpu_ds
, fpu_mxcsr
, fpu_mxcsrmask
, fpu_stmm0
, fpu_stmm1
,
439 fpu_stmm2
, fpu_stmm3
, fpu_stmm4
, fpu_stmm5
, fpu_stmm6
, fpu_stmm7
,
440 fpu_xmm0
, fpu_xmm1
, fpu_xmm2
, fpu_xmm3
, fpu_xmm4
, fpu_xmm5
,
443 // Exception registers
445 static uint32_t g_exc_regnums
[] = {exc_trapno
, exc_err
, exc_faultvaddr
};
447 // Number of registers in each register set
448 const size_t k_num_gpr_registers
= std::size(g_gpr_regnums
);
449 const size_t k_num_fpu_registers
= std::size(g_fpu_regnums
);
450 const size_t k_num_exc_registers
= std::size(g_exc_regnums
);
452 // Register set definitions. The first definitions at register set index of
453 // zero is for all registers, followed by other registers sets. The register
454 // information for the all register set need not be filled in.
455 static const RegisterSet g_reg_sets
[] = {
457 "General Purpose Registers", "gpr", k_num_gpr_registers
, g_gpr_regnums
,
459 {"Floating Point Registers", "fpu", k_num_fpu_registers
, g_fpu_regnums
},
460 {"Exception State Registers", "exc", k_num_exc_registers
, g_exc_regnums
}};
462 const size_t k_num_regsets
= std::size(g_reg_sets
);
464 size_t RegisterContextDarwin_i386::GetRegisterSetCount() {
465 return k_num_regsets
;
468 const RegisterSet
*RegisterContextDarwin_i386::GetRegisterSet(size_t reg_set
) {
469 if (reg_set
< k_num_regsets
)
470 return &g_reg_sets
[reg_set
];
474 // Register information definitions for 32 bit i386.
475 int RegisterContextDarwin_i386::GetSetForNativeRegNum(int reg_num
) {
476 if (reg_num
< fpu_fcw
)
478 else if (reg_num
< exc_trapno
)
480 else if (reg_num
< k_num_registers
)
485 void RegisterContextDarwin_i386::LogGPR(Log
*log
, const char *title
) {
488 LLDB_LOGF(log
, "%s", title
);
489 for (uint32_t i
= 0; i
< k_num_gpr_registers
; i
++) {
490 uint32_t reg
= gpr_eax
+ i
;
491 LLDB_LOGF(log
, "%12s = 0x%8.8x", g_register_infos
[reg
].name
,
497 int RegisterContextDarwin_i386::ReadGPR(bool force
) {
499 if (force
|| !RegisterSetIsCached(set
)) {
500 SetError(set
, Read
, DoReadGPR(GetThreadID(), set
, gpr
));
502 return GetError(set
, Read
);
505 int RegisterContextDarwin_i386::ReadFPU(bool force
) {
507 if (force
|| !RegisterSetIsCached(set
)) {
508 SetError(set
, Read
, DoReadFPU(GetThreadID(), set
, fpu
));
510 return GetError(set
, Read
);
513 int RegisterContextDarwin_i386::ReadEXC(bool force
) {
515 if (force
|| !RegisterSetIsCached(set
)) {
516 SetError(set
, Read
, DoReadEXC(GetThreadID(), set
, exc
));
518 return GetError(set
, Read
);
521 int RegisterContextDarwin_i386::WriteGPR() {
523 if (!RegisterSetIsCached(set
)) {
524 SetError(set
, Write
, -1);
527 SetError(set
, Write
, DoWriteGPR(GetThreadID(), set
, gpr
));
528 SetError(set
, Read
, -1);
529 return GetError(set
, Write
);
532 int RegisterContextDarwin_i386::WriteFPU() {
534 if (!RegisterSetIsCached(set
)) {
535 SetError(set
, Write
, -1);
538 SetError(set
, Write
, DoWriteFPU(GetThreadID(), set
, fpu
));
539 SetError(set
, Read
, -1);
540 return GetError(set
, Write
);
543 int RegisterContextDarwin_i386::WriteEXC() {
545 if (!RegisterSetIsCached(set
)) {
546 SetError(set
, Write
, -1);
549 SetError(set
, Write
, DoWriteEXC(GetThreadID(), set
, exc
));
550 SetError(set
, Read
, -1);
551 return GetError(set
, Write
);
554 int RegisterContextDarwin_i386::ReadRegisterSet(uint32_t set
, bool force
) {
557 return ReadGPR(force
);
559 return ReadFPU(force
);
561 return ReadEXC(force
);
568 int RegisterContextDarwin_i386::WriteRegisterSet(uint32_t set
) {
569 // Make sure we have a valid context to set.
570 if (RegisterSetIsCached(set
)) {
585 bool RegisterContextDarwin_i386::ReadRegister(const RegisterInfo
*reg_info
,
586 RegisterValue
&value
) {
587 const uint32_t reg
= reg_info
->kinds
[eRegisterKindLLDB
];
588 int set
= RegisterContextDarwin_i386::GetSetForNativeRegNum(reg
);
593 if (ReadRegisterSet(set
, false) != 0)
613 value
= (&gpr
.eax
)[reg
- gpr_eax
];
653 value
= fpu
.mxcsrmask
;
664 // These values don't fit into scalar types,
665 // RegisterContext::ReadRegisterBytes() must be used for these registers
666 //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes,
678 // These values don't fit into scalar types,
679 // RegisterContext::ReadRegisterBytes() must be used for these registers
680 //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes,
693 value
= exc
.faultvaddr
;
702 bool RegisterContextDarwin_i386::WriteRegister(const RegisterInfo
*reg_info
,
703 const RegisterValue
&value
) {
704 const uint32_t reg
= reg_info
->kinds
[eRegisterKindLLDB
];
705 int set
= GetSetForNativeRegNum(reg
);
710 if (ReadRegisterSet(set
, false) != 0)
730 (&gpr
.eax
)[reg
- gpr_eax
] = value
.GetAsUInt32();
734 fpu
.fcw
= value
.GetAsUInt16();
738 fpu
.fsw
= value
.GetAsUInt16();
742 fpu
.ftw
= value
.GetAsUInt8();
746 fpu
.fop
= value
.GetAsUInt16();
750 fpu
.ip
= value
.GetAsUInt32();
754 fpu
.cs
= value
.GetAsUInt16();
758 fpu
.dp
= value
.GetAsUInt32();
762 fpu
.ds
= value
.GetAsUInt16();
766 fpu
.mxcsr
= value
.GetAsUInt32();
770 fpu
.mxcsrmask
= value
.GetAsUInt32();
781 // These values don't fit into scalar types,
782 // RegisterContext::ReadRegisterBytes() must be used for these registers
783 ::memcpy(fpu
.stmm
[reg
- fpu_stmm0
].bytes
, value
.GetBytes(),
784 value
.GetByteSize());
795 // These values don't fit into scalar types,
796 // RegisterContext::ReadRegisterBytes() must be used for these registers
797 ::memcpy(fpu
.xmm
[reg
- fpu_xmm0
].bytes
, value
.GetBytes(),
798 value
.GetByteSize());
802 exc
.trapno
= value
.GetAsUInt32();
806 exc
.err
= value
.GetAsUInt32();
810 exc
.faultvaddr
= value
.GetAsUInt32();
816 return WriteRegisterSet(set
) == 0;
819 bool RegisterContextDarwin_i386::ReadAllRegisterValues(
820 lldb::WritableDataBufferSP
&data_sp
) {
821 data_sp
= std::make_shared
<DataBufferHeap
>(REG_CONTEXT_SIZE
, 0);
822 if (ReadGPR(false) == 0 && ReadFPU(false) == 0 && ReadEXC(false) == 0) {
823 uint8_t *dst
= data_sp
->GetBytes();
824 ::memcpy(dst
, &gpr
, sizeof(gpr
));
827 ::memcpy(dst
, &fpu
, sizeof(fpu
));
830 ::memcpy(dst
, &exc
, sizeof(exc
));
836 bool RegisterContextDarwin_i386::WriteAllRegisterValues(
837 const lldb::DataBufferSP
&data_sp
) {
838 if (data_sp
&& data_sp
->GetByteSize() == REG_CONTEXT_SIZE
) {
839 const uint8_t *src
= data_sp
->GetBytes();
840 ::memcpy(&gpr
, src
, sizeof(gpr
));
843 ::memcpy(&fpu
, src
, sizeof(fpu
));
846 ::memcpy(&exc
, src
, sizeof(exc
));
847 uint32_t success_count
= 0;
854 return success_count
== 3;
859 uint32_t RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber(
860 lldb::RegisterKind kind
, uint32_t reg
) {
861 if (kind
== eRegisterKindGeneric
) {
863 case LLDB_REGNUM_GENERIC_PC
:
865 case LLDB_REGNUM_GENERIC_SP
:
867 case LLDB_REGNUM_GENERIC_FP
:
869 case LLDB_REGNUM_GENERIC_FLAGS
:
871 case LLDB_REGNUM_GENERIC_RA
:
875 } else if (kind
== eRegisterKindEHFrame
|| kind
== eRegisterKindDWARF
) {
932 } else if (kind
== eRegisterKindLLDB
) {
935 return LLDB_INVALID_REGNUM
;
938 bool RegisterContextDarwin_i386::HardwareSingleStep(bool enable
) {
939 if (ReadGPR(false) != 0)
942 const uint32_t trace_bit
= 0x100u
;
944 // If the trace bit is already set, there is nothing to do
945 if (gpr
.eflags
& trace_bit
)
948 gpr
.eflags
|= trace_bit
;
950 // If the trace bit is already cleared, there is nothing to do
951 if (gpr
.eflags
& trace_bit
)
952 gpr
.eflags
&= ~trace_bit
;
957 return WriteGPR() == 0;