1 //===----------------------- ABISysV_i386.cpp -------------------*- C++ -*-===//
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
6 //===----------------------------------------------------------------------===//
8 #include "ABISysV_i386.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/Triple.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/PluginManager.h"
15 #include "lldb/Core/Value.h"
16 #include "lldb/Core/ValueObjectConstResult.h"
17 #include "lldb/Core/ValueObjectMemory.h"
18 #include "lldb/Core/ValueObjectRegister.h"
19 #include "lldb/Symbol/UnwindPlan.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/RegisterContext.h"
22 #include "lldb/Target/StackFrame.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Utility/ConstString.h"
26 #include "lldb/Utility/DataExtractor.h"
27 #include "lldb/Utility/Log.h"
28 #include "lldb/Utility/RegisterValue.h"
29 #include "lldb/Utility/Status.h"
32 using namespace lldb_private;
34 // This source file uses the following document as a reference:
35 //====================================================================
36 // System V Application Binary Interface
37 // Intel386 Architecture Processor Supplement, Version 1.0
39 // H.J. Lu, David L Kreitzer, Milind Girkar, Zia Ansari
42 // System V Application Binary Interface,
43 // AMD64 Architecture Processor Supplement,
45 // H.J. Lu, Michael Matz, Milind Girkar, Jan Hubicka,
46 // Andreas Jaeger, Mark Mitchell)
49 //====================================================================
51 // DWARF Register Number Mapping
52 // See Table 2.14 of the reference document (specified on top of this file)
53 // Comment: Table 2.14 is followed till 'mm' entries. After that, all entries
85 dwarf_ymm0 = dwarf_xmm0,
86 dwarf_ymm1 = dwarf_xmm1,
87 dwarf_ymm2 = dwarf_xmm2,
88 dwarf_ymm3 = dwarf_xmm3,
89 dwarf_ymm4 = dwarf_xmm4,
90 dwarf_ymm5 = dwarf_xmm5,
91 dwarf_ymm6 = dwarf_xmm6,
92 dwarf_ymm7 = dwarf_xmm7,
109 static RegisterInfo g_register_infos[] = {
111 //NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB NATIVE VALUE INVAL DYN EXPR SZ
112 //========== ======= == === ============= ==================== =================== =================== ========================= =================== =================== ======= ======= ======== ==
113 {"eax", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_eax, dwarf_eax, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
114 {"ebx", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
115 {"ecx", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_ecx, dwarf_ecx, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
116 {"edx", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_edx, dwarf_edx, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
117 {"esi", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_esi, dwarf_esi, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
118 {"edi", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_edi, dwarf_edi, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
119 {"ebp", "fp", 4, 0, eEncodingUint, eFormatHex, {dwarf_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
120 {"esp", "sp", 4, 0, eEncodingUint, eFormatHex, {dwarf_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
121 {"eip", "pc", 4, 0, eEncodingUint, eFormatHex, {dwarf_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
122 {"eflags", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
123 {"cs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
124 {"ss", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
125 {"ds", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
126 {"es", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
127 {"fs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
128 {"gs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
129 {"st0", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
130 {"st1", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
131 {"st2", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
132 {"st3", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
133 {"st4", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
134 {"st5", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
135 {"st6", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
136 {"st7", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
137 {"fctrl", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
138 {"fstat", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
139 {"ftag", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
140 {"fiseg", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
141 {"fioff", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
142 {"foseg", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
143 {"fooff", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
144 {"fop", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
145 {"xmm0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
146 {"xmm1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
147 {"xmm2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
148 {"xmm3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
149 {"xmm4", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
150 {"xmm5", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
151 {"xmm6", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
152 {"xmm7", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
153 {"mxcsr", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
154 {"ymm0", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
155 {"ymm1", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
156 {"ymm2", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
157 {"ymm3", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
158 {"ymm4", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
159 {"ymm5", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
160 {"ymm6", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
161 {"ymm7", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
162 {"bnd0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd0, dwarf_bnd0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
163 {"bnd1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd1, dwarf_bnd1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
164 {"bnd2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd2, dwarf_bnd2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
165 {"bnd3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd3, dwarf_bnd3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
166 {"bndcfgu", nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0},
167 {"bndstatus",nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}
171 static const uint32_t k_num_register_infos =
172 llvm::array_lengthof(g_register_infos);
173 static bool g_register_info_names_constified = false;
175 const lldb_private::RegisterInfo *
176 ABISysV_i386::GetRegisterInfoArray(uint32_t &count) {
177 // Make the C-string names and alt_names for the register infos into const
178 // C-string values by having the ConstString unique the names in the global
179 // constant C-string pool.
180 if (!g_register_info_names_constified) {
181 g_register_info_names_constified = true;
182 for (uint32_t i = 0; i < k_num_register_infos; ++i) {
183 if (g_register_infos[i].name)
184 g_register_infos[i].name =
185 ConstString(g_register_infos[i].name).GetCString();
186 if (g_register_infos[i].alt_name)
187 g_register_infos[i].alt_name =
188 ConstString(g_register_infos[i].alt_name).GetCString();
191 count = k_num_register_infos;
192 return g_register_infos;
198 ABISysV_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
199 if (arch.GetTriple().getVendor() != llvm::Triple::Apple) {
200 if (arch.GetTriple().getArch() == llvm::Triple::x86) {
201 return ABISP(new ABISysV_i386(process_sp));
207 bool ABISysV_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
208 addr_t func_addr, addr_t return_addr,
209 llvm::ArrayRef<addr_t> args) const {
210 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
215 uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
216 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
217 uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
218 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
220 // While using register info to write a register value to memory, the
221 // register info just needs to have the correct size of a 32 bit register,
222 // the actual register it pertains to is not important, just the size needs
223 // to be correct. "eax" is used here for this purpose.
224 const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
226 return false; // TODO this should actually never happen
229 RegisterValue reg_value;
231 // Make room for the argument(s) on the stack
232 sp -= 4 * args.size();
235 sp &= ~(16ull - 1ull); // 16-byte alignment
237 // Write arguments onto the stack
239 for (addr_t arg : args) {
240 reg_value.SetUInt32(arg);
241 error = reg_ctx->WriteRegisterValueToMemory(
242 reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
248 // The return address is pushed onto the stack
250 reg_value.SetUInt32(return_addr);
251 error = reg_ctx->WriteRegisterValueToMemory(
252 reg_info_32, sp, reg_info_32->byte_size, reg_value);
256 // Setting %esp to the actual stack value.
257 if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
260 // Setting %eip to the address of the called function.
261 if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
267 static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
268 bool is_signed, Process *process,
269 addr_t ¤t_stack_argument) {
270 uint32_t byte_size = (bit_width + (8 - 1)) / 8;
276 if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
277 is_signed, scalar, error)) {
278 current_stack_argument += byte_size;
284 bool ABISysV_i386::GetArgumentValues(Thread &thread, ValueList &values) const {
285 unsigned int num_values = values.GetSize();
286 unsigned int value_index;
288 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
293 // Get pointer to the first stack argument
294 addr_t sp = reg_ctx->GetSP(0);
298 addr_t current_stack_argument = sp + 4; // jump over return address
300 for (value_index = 0; value_index < num_values; ++value_index) {
301 Value *value = values.GetValueAtIndex(value_index);
306 // Currently: Support for extracting values with Clang QualTypes only.
307 CompilerType compiler_type(value->GetCompilerType());
308 llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
311 if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
312 ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
313 thread.GetProcess().get(), current_stack_argument);
314 } else if (compiler_type.IsPointerType()) {
315 ReadIntegerArgument(value->GetScalar(), *bit_size, false,
316 thread.GetProcess().get(), current_stack_argument);
323 Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
324 lldb::ValueObjectSP &new_value_sp) {
327 error.SetErrorString("Empty value object for return value.");
331 CompilerType compiler_type = new_value_sp->GetCompilerType();
332 if (!compiler_type) {
333 error.SetErrorString("Null clang type for return value.");
337 const uint32_t type_flags = compiler_type.GetTypeInfo();
338 Thread *thread = frame_sp->GetThread().get();
339 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
342 size_t num_bytes = new_value_sp->GetData(data, data_error);
343 bool register_write_successful = true;
345 if (data_error.Fail()) {
346 error.SetErrorStringWithFormat(
347 "Couldn't convert return value to raw data: %s",
348 data_error.AsCString());
352 // Following "IF ELSE" block categorizes various 'Fundamental Data Types'.
353 // The terminology 'Fundamental Data Types' used here is adopted from Table
354 // 2.1 of the reference document (specified on top of this file)
356 if (type_flags & eTypeIsPointer) // 'Pointer'
358 if (num_bytes != sizeof(uint32_t)) {
359 error.SetErrorString("Pointer to be returned is not 4 bytes wide");
362 lldb::offset_t offset = 0;
363 const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
364 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
365 register_write_successful =
366 reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
367 } else if ((type_flags & eTypeIsScalar) ||
368 (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'
370 lldb::offset_t offset = 0;
371 const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
373 if (type_flags & eTypeIsInteger) // 'Integral' except enum
379 // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to
383 uint32_t raw_value_low = data.GetMaxU32(&offset, 4);
384 const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0);
385 uint32_t raw_value_high = data.GetMaxU32(&offset, num_bytes - offset);
386 register_write_successful =
387 (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value_low) &&
388 reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value_high));
394 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
395 register_write_successful =
396 reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
400 } else if (type_flags & eTypeIsEnumeration) // handles enum
402 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
403 register_write_successful =
404 reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
405 } else if (type_flags & eTypeIsFloat) // 'Floating Point'
407 RegisterValue st0_value, fstat_value, ftag_value;
408 const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);
409 const RegisterInfo *fstat_info =
410 reg_ctx->GetRegisterInfoByName("fstat", 0);
411 const RegisterInfo *ftag_info = reg_ctx->GetRegisterInfoByName("ftag", 0);
413 /* According to Page 3-12 of document
414 System V Application Binary Interface, Intel386 Architecture Processor
415 Supplement, Fourth Edition
416 To return Floating Point values, all st% registers except st0 should be
417 empty after exiting from
418 a function. This requires setting fstat and ftag registers to specific
420 fstat: The TOP field of fstat should be set to a value [0,7]. ABI doesn't
422 value of TOP in case of function return. Hence, we set the TOP field to 7
424 uint32_t value_fstat_u32 = 0x00003800;
426 /* ftag: Implication of setting TOP to 7 and indicating all st% registers
427 empty except st0 is to set
428 7th bit of 4th byte of FXSAVE area to 1 and all other bits of this byte to
429 0. This is in accordance
430 with the document Intel 64 and IA-32 Architectures Software Developer's
431 Manual, January 2015 */
432 uint32_t value_ftag_u32 = 0x00000080;
434 if (num_bytes <= 12) // handles float, double, long double, __float80
436 long double value_long_dbl = 0.0;
438 value_long_dbl = data.GetFloat(&offset);
439 else if (num_bytes == 8)
440 value_long_dbl = data.GetDouble(&offset);
441 else if (num_bytes == 12)
442 value_long_dbl = data.GetLongDouble(&offset);
444 error.SetErrorString("Invalid number of bytes for this return type");
447 st0_value.SetLongDouble(value_long_dbl);
448 fstat_value.SetUInt32(value_fstat_u32);
449 ftag_value.SetUInt32(value_ftag_u32);
450 register_write_successful =
451 reg_ctx->WriteRegister(st0_info, st0_value) &&
452 reg_ctx->WriteRegister(fstat_info, fstat_value) &&
453 reg_ctx->WriteRegister(ftag_info, ftag_value);
454 } else if (num_bytes == 16) // handles __float128
456 error.SetErrorString("Implementation is missing for this clang type.");
459 // Neither 'Integral' nor 'Floating Point'. If flow reaches here then
460 // check type_flags. This type_flags is not a valid type.
461 error.SetErrorString("Invalid clang type");
464 /* 'Complex Floating Point', 'Packed', 'Decimal Floating Point' and
465 'Aggregate' data types
466 are yet to be implemented */
467 error.SetErrorString("Currently only Integral and Floating Point clang "
468 "types are supported.");
470 if (!register_write_successful)
471 error.SetErrorString("Register writing failed");
475 ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple(
476 Thread &thread, CompilerType &return_compiler_type) const {
477 ValueObjectSP return_valobj_sp;
480 if (!return_compiler_type)
481 return return_valobj_sp;
483 value.SetCompilerType(return_compiler_type);
485 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
487 return return_valobj_sp;
489 const uint32_t type_flags = return_compiler_type.GetTypeInfo();
492 reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
494 reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
496 // Following "IF ELSE" block categorizes various 'Fundamental Data Types'.
497 // The terminology 'Fundamental Data Types' used here is adopted from Table
498 // 2.1 of the reference document (specified on top of this file)
500 if (type_flags & eTypeIsPointer) // 'Pointer'
503 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
505 value.SetValueType(Value::eValueTypeScalar);
506 value.GetScalar() = ptr;
507 return_valobj_sp = ValueObjectConstResult::Create(
508 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
509 } else if ((type_flags & eTypeIsScalar) ||
510 (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'
512 value.SetValueType(Value::eValueTypeScalar);
513 llvm::Optional<uint64_t> byte_size =
514 return_compiler_type.GetByteSize(nullptr);
516 return return_valobj_sp;
517 bool success = false;
519 if (type_flags & eTypeIsInteger) // 'Integral' except enum
521 const bool is_signed = ((type_flags & eTypeIsSigned) != 0);
523 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
526 (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
530 switch (*byte_size) {
535 // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to
541 value.GetScalar() = (int64_t)(raw_value);
543 value.GetScalar() = (uint64_t)(raw_value);
549 value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
551 value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
557 value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
559 value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
565 value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
567 value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
573 return_valobj_sp = ValueObjectConstResult::Create(
574 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
575 } else if (type_flags & eTypeIsEnumeration) // handles enum
578 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
580 value.SetValueType(Value::eValueTypeScalar);
581 value.GetScalar() = enm;
582 return_valobj_sp = ValueObjectConstResult::Create(
583 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
584 } else if (type_flags & eTypeIsFloat) // 'Floating Point'
586 if (*byte_size <= 12) // handles float, double, long double, __float80
588 const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);
589 RegisterValue st0_value;
591 if (reg_ctx->ReadRegister(st0_info, st0_value)) {
593 if (st0_value.GetData(data)) {
594 lldb::offset_t offset = 0;
595 long double value_long_double = data.GetLongDouble(&offset);
598 if (*byte_size == 4) {
599 float value_float = (float)value_long_double;
600 value.GetScalar() = value_float;
602 } else if (*byte_size == 8) {
604 // On Android Platform: long double is also 8 bytes It will be
605 // handled here only.
606 double value_double = (double)value_long_double;
607 value.GetScalar() = value_double;
609 } else if (*byte_size == 12) {
610 // long double and __float80 are 12 bytes on i386.
611 value.GetScalar() = value_long_double;
618 return_valobj_sp = ValueObjectConstResult::Create(
619 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
620 } else if (*byte_size == 16) // handles __float128
622 lldb::addr_t storage_addr = (uint32_t)(
623 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
625 return_valobj_sp = ValueObjectMemory::Create(
626 &thread, "", Address(storage_addr, nullptr), return_compiler_type);
628 } else // Neither 'Integral' nor 'Floating Point'
630 // If flow reaches here then check type_flags This type_flags is
633 } else if (type_flags & eTypeIsComplex) // 'Complex Floating Point'
635 // ToDo: Yet to be implemented
636 } else if (type_flags & eTypeIsVector) // 'Packed'
638 llvm::Optional<uint64_t> byte_size =
639 return_compiler_type.GetByteSize(nullptr);
640 if (byte_size && *byte_size > 0) {
641 const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0);
642 if (vec_reg == nullptr)
643 vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
646 if (*byte_size <= vec_reg->byte_size) {
647 ProcessSP process_sp(thread.GetProcess());
649 std::unique_ptr<DataBufferHeap> heap_data_up(
650 new DataBufferHeap(*byte_size, 0));
651 const ByteOrder byte_order = process_sp->GetByteOrder();
652 RegisterValue reg_value;
653 if (reg_ctx->ReadRegister(vec_reg, reg_value)) {
655 if (reg_value.GetAsMemoryData(vec_reg, heap_data_up->GetBytes(),
656 heap_data_up->GetByteSize(),
657 byte_order, error)) {
658 DataExtractor data(DataBufferSP(heap_data_up.release()),
660 process_sp->GetTarget()
662 .GetAddressByteSize());
663 return_valobj_sp = ValueObjectConstResult::Create(
664 &thread, return_compiler_type, ConstString(""), data);
668 } else if (*byte_size <= vec_reg->byte_size * 2) {
669 const RegisterInfo *vec_reg2 =
670 reg_ctx->GetRegisterInfoByName("xmm1", 0);
672 ProcessSP process_sp(thread.GetProcess());
674 std::unique_ptr<DataBufferHeap> heap_data_up(
675 new DataBufferHeap(*byte_size, 0));
676 const ByteOrder byte_order = process_sp->GetByteOrder();
677 RegisterValue reg_value;
678 RegisterValue reg_value2;
679 if (reg_ctx->ReadRegister(vec_reg, reg_value) &&
680 reg_ctx->ReadRegister(vec_reg2, reg_value2)) {
683 if (reg_value.GetAsMemoryData(vec_reg, heap_data_up->GetBytes(),
684 vec_reg->byte_size, byte_order,
686 reg_value2.GetAsMemoryData(
687 vec_reg2, heap_data_up->GetBytes() + vec_reg->byte_size,
688 heap_data_up->GetByteSize() - vec_reg->byte_size,
689 byte_order, error)) {
690 DataExtractor data(DataBufferSP(heap_data_up.release()),
692 process_sp->GetTarget()
694 .GetAddressByteSize());
695 return_valobj_sp = ValueObjectConstResult::Create(
696 &thread, return_compiler_type, ConstString(""), data);
704 } else // 'Decimal Floating Point'
706 // ToDo: Yet to be implemented
708 return return_valobj_sp;
711 ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl(
712 Thread &thread, CompilerType &return_compiler_type) const {
713 ValueObjectSP return_valobj_sp;
715 if (!return_compiler_type)
716 return return_valobj_sp;
718 ExecutionContext exe_ctx(thread.shared_from_this());
719 return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type);
720 if (return_valobj_sp)
721 return return_valobj_sp;
723 RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
725 return return_valobj_sp;
727 if (return_compiler_type.IsAggregateType()) {
729 reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
730 lldb::addr_t storage_addr = (uint32_t)(
731 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
733 return_valobj_sp = ValueObjectMemory::Create(
734 &thread, "", Address(storage_addr, nullptr), return_compiler_type);
737 return return_valobj_sp;
740 // This defines CFA as esp+4
741 // The saved pc is at CFA-4 (i.e. esp+0)
742 // The saved esp is CFA+0
744 bool ABISysV_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
746 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
748 uint32_t sp_reg_num = dwarf_esp;
749 uint32_t pc_reg_num = dwarf_eip;
751 UnwindPlan::RowSP row(new UnwindPlan::Row);
752 row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
753 row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
754 row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
755 unwind_plan.AppendRow(row);
756 unwind_plan.SetSourceName("i386 at-func-entry default");
757 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
761 // This defines CFA as ebp+8
762 // The saved pc is at CFA-4 (i.e. ebp+4)
763 // The saved ebp is at CFA-8 (i.e. ebp+0)
764 // The saved esp is CFA+0
766 bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
768 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
770 uint32_t fp_reg_num = dwarf_ebp;
771 uint32_t sp_reg_num = dwarf_esp;
772 uint32_t pc_reg_num = dwarf_eip;
774 UnwindPlan::RowSP row(new UnwindPlan::Row);
775 const int32_t ptr_size = 4;
777 row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
780 row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
781 row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
782 row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
784 unwind_plan.AppendRow(row);
785 unwind_plan.SetSourceName("i386 default unwind plan");
786 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
787 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
791 // According to "Register Usage" in reference document (specified on top of
792 // this source file) ebx, ebp, esi, edi and esp registers are preserved i.e.
793 // non-volatile i.e. callee-saved on i386
794 bool ABISysV_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
798 // Saved registers are ebx, ebp, esi, edi, esp, eip
799 const char *name = reg_info->name;
800 if (name[0] == 'e') {
803 if (name[2] == 'x' || name[2] == 'p')
804 return name[3] == '\0';
808 return name[3] == '\0';
812 return name[3] == '\0';
815 if (name[2] == 'i' || name[2] == 'p')
816 return name[3] == '\0';
821 if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
823 if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
825 if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
831 void ABISysV_i386::Initialize() {
832 PluginManager::RegisterPlugin(
833 GetPluginNameStatic(), "System V ABI for i386 targets", CreateInstance);
836 void ABISysV_i386::Terminate() {
837 PluginManager::UnregisterPlugin(CreateInstance);
840 // PluginInterface protocol
842 lldb_private::ConstString ABISysV_i386::GetPluginNameStatic() {
843 static ConstString g_name("sysv-i386");
847 lldb_private::ConstString ABISysV_i386::GetPluginName() {
848 return GetPluginNameStatic();