/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- ABISysV_i386.cpp --------------------------------------------------===// |
2 | | // |
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 | | //===----------------------------------------------------------------------===// |
7 | | |
8 | | #include "ABISysV_i386.h" |
9 | | |
10 | | #include "llvm/ADT/STLExtras.h" |
11 | | #include "llvm/TargetParser/Triple.h" |
12 | | |
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" |
30 | | #include <optional> |
31 | | |
32 | | using namespace lldb; |
33 | | using namespace lldb_private; |
34 | | |
35 | | LLDB_PLUGIN_DEFINE(ABISysV_i386) |
36 | | |
37 | | // This source file uses the following document as a reference: |
38 | | //==================================================================== |
39 | | // System V Application Binary Interface |
40 | | // Intel386 Architecture Processor Supplement, Version 1.0 |
41 | | // Edited by |
42 | | // H.J. Lu, David L Kreitzer, Milind Girkar, Zia Ansari |
43 | | // |
44 | | // (Based on |
45 | | // System V Application Binary Interface, |
46 | | // AMD64 Architecture Processor Supplement, |
47 | | // Edited by |
48 | | // H.J. Lu, Michael Matz, Milind Girkar, Jan Hubicka, |
49 | | // Andreas Jaeger, Mark Mitchell) |
50 | | // |
51 | | // February 3, 2015 |
52 | | //==================================================================== |
53 | | |
54 | | // DWARF Register Number Mapping |
55 | | // See Table 2.14 of the reference document (specified on top of this file) |
56 | | // Comment: Table 2.14 is followed till 'mm' entries. After that, all entries |
57 | | // are ignored here. |
58 | | |
59 | | enum dwarf_regnums { |
60 | | dwarf_eax = 0, |
61 | | dwarf_ecx, |
62 | | dwarf_edx, |
63 | | dwarf_ebx, |
64 | | dwarf_esp, |
65 | | dwarf_ebp, |
66 | | dwarf_esi, |
67 | | dwarf_edi, |
68 | | dwarf_eip, |
69 | | }; |
70 | | |
71 | | // Static Functions |
72 | | |
73 | | ABISP |
74 | 4.66k | ABISysV_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { |
75 | 4.66k | if (arch.GetTriple().getVendor() != llvm::Triple::Apple) { |
76 | 347 | if (arch.GetTriple().getArch() == llvm::Triple::x86) { |
77 | 34 | return ABISP( |
78 | 34 | new ABISysV_i386(std::move(process_sp), MakeMCRegisterInfo(arch))); |
79 | 34 | } |
80 | 347 | } |
81 | 4.63k | return ABISP(); |
82 | 4.66k | } |
83 | | |
84 | | bool ABISysV_i386::PrepareTrivialCall(Thread &thread, addr_t sp, |
85 | | addr_t func_addr, addr_t return_addr, |
86 | 0 | llvm::ArrayRef<addr_t> args) const { |
87 | 0 | RegisterContext *reg_ctx = thread.GetRegisterContext().get(); |
88 | |
|
89 | 0 | if (!reg_ctx) |
90 | 0 | return false; |
91 | | |
92 | 0 | uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( |
93 | 0 | eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); |
94 | 0 | uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( |
95 | 0 | eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); |
96 | | |
97 | | // While using register info to write a register value to memory, the |
98 | | // register info just needs to have the correct size of a 32 bit register, |
99 | | // the actual register it pertains to is not important, just the size needs |
100 | | // to be correct. "eax" is used here for this purpose. |
101 | 0 | const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax"); |
102 | 0 | if (!reg_info_32) |
103 | 0 | return false; // TODO this should actually never happen |
104 | | |
105 | 0 | Status error; |
106 | 0 | RegisterValue reg_value; |
107 | | |
108 | | // Make room for the argument(s) on the stack |
109 | 0 | sp -= 4 * args.size(); |
110 | | |
111 | | // SP Alignment |
112 | 0 | sp &= ~(16ull - 1ull); // 16-byte alignment |
113 | | |
114 | | // Write arguments onto the stack |
115 | 0 | addr_t arg_pos = sp; |
116 | 0 | for (addr_t arg : args) { |
117 | 0 | reg_value.SetUInt32(arg); |
118 | 0 | error = reg_ctx->WriteRegisterValueToMemory( |
119 | 0 | reg_info_32, arg_pos, reg_info_32->byte_size, reg_value); |
120 | 0 | if (error.Fail()) |
121 | 0 | return false; |
122 | 0 | arg_pos += 4; |
123 | 0 | } |
124 | | |
125 | | // The return address is pushed onto the stack |
126 | 0 | sp -= 4; |
127 | 0 | reg_value.SetUInt32(return_addr); |
128 | 0 | error = reg_ctx->WriteRegisterValueToMemory( |
129 | 0 | reg_info_32, sp, reg_info_32->byte_size, reg_value); |
130 | 0 | if (error.Fail()) |
131 | 0 | return false; |
132 | | |
133 | | // Setting %esp to the actual stack value. |
134 | 0 | if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp)) |
135 | 0 | return false; |
136 | | |
137 | | // Setting %eip to the address of the called function. |
138 | 0 | if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr)) |
139 | 0 | return false; |
140 | | |
141 | 0 | return true; |
142 | 0 | } |
143 | | |
144 | | static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, |
145 | | bool is_signed, Process *process, |
146 | 0 | addr_t ¤t_stack_argument) { |
147 | 0 | uint32_t byte_size = (bit_width + (8 - 1)) / 8; |
148 | 0 | Status error; |
149 | |
|
150 | 0 | if (!process) |
151 | 0 | return false; |
152 | | |
153 | 0 | if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, |
154 | 0 | is_signed, scalar, error)) { |
155 | 0 | current_stack_argument += byte_size; |
156 | 0 | return true; |
157 | 0 | } |
158 | 0 | return false; |
159 | 0 | } |
160 | | |
161 | 0 | bool ABISysV_i386::GetArgumentValues(Thread &thread, ValueList &values) const { |
162 | 0 | unsigned int num_values = values.GetSize(); |
163 | 0 | unsigned int value_index; |
164 | |
|
165 | 0 | RegisterContext *reg_ctx = thread.GetRegisterContext().get(); |
166 | |
|
167 | 0 | if (!reg_ctx) |
168 | 0 | return false; |
169 | | |
170 | | // Get pointer to the first stack argument |
171 | 0 | addr_t sp = reg_ctx->GetSP(0); |
172 | 0 | if (!sp) |
173 | 0 | return false; |
174 | | |
175 | 0 | addr_t current_stack_argument = sp + 4; // jump over return address |
176 | |
|
177 | 0 | for (value_index = 0; value_index < num_values; ++value_index) { |
178 | 0 | Value *value = values.GetValueAtIndex(value_index); |
179 | |
|
180 | 0 | if (!value) |
181 | 0 | return false; |
182 | | |
183 | | // Currently: Support for extracting values with Clang QualTypes only. |
184 | 0 | CompilerType compiler_type(value->GetCompilerType()); |
185 | 0 | std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); |
186 | 0 | if (bit_size) { |
187 | 0 | bool is_signed; |
188 | 0 | if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { |
189 | 0 | ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, |
190 | 0 | thread.GetProcess().get(), current_stack_argument); |
191 | 0 | } else if (compiler_type.IsPointerType()) { |
192 | 0 | ReadIntegerArgument(value->GetScalar(), *bit_size, false, |
193 | 0 | thread.GetProcess().get(), current_stack_argument); |
194 | 0 | } |
195 | 0 | } |
196 | 0 | } |
197 | 0 | return true; |
198 | 0 | } |
199 | | |
200 | | Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, |
201 | 0 | lldb::ValueObjectSP &new_value_sp) { |
202 | 0 | Status error; |
203 | 0 | if (!new_value_sp) { |
204 | 0 | error.SetErrorString("Empty value object for return value."); |
205 | 0 | return error; |
206 | 0 | } |
207 | | |
208 | 0 | CompilerType compiler_type = new_value_sp->GetCompilerType(); |
209 | 0 | if (!compiler_type) { |
210 | 0 | error.SetErrorString("Null clang type for return value."); |
211 | 0 | return error; |
212 | 0 | } |
213 | | |
214 | 0 | const uint32_t type_flags = compiler_type.GetTypeInfo(); |
215 | 0 | Thread *thread = frame_sp->GetThread().get(); |
216 | 0 | RegisterContext *reg_ctx = thread->GetRegisterContext().get(); |
217 | 0 | DataExtractor data; |
218 | 0 | Status data_error; |
219 | 0 | size_t num_bytes = new_value_sp->GetData(data, data_error); |
220 | 0 | bool register_write_successful = true; |
221 | |
|
222 | 0 | if (data_error.Fail()) { |
223 | 0 | error.SetErrorStringWithFormat( |
224 | 0 | "Couldn't convert return value to raw data: %s", |
225 | 0 | data_error.AsCString()); |
226 | 0 | return error; |
227 | 0 | } |
228 | | |
229 | | // Following "IF ELSE" block categorizes various 'Fundamental Data Types'. |
230 | | // The terminology 'Fundamental Data Types' used here is adopted from Table |
231 | | // 2.1 of the reference document (specified on top of this file) |
232 | | |
233 | 0 | if (type_flags & eTypeIsPointer) // 'Pointer' |
234 | 0 | { |
235 | 0 | if (num_bytes != sizeof(uint32_t)) { |
236 | 0 | error.SetErrorString("Pointer to be returned is not 4 bytes wide"); |
237 | 0 | return error; |
238 | 0 | } |
239 | 0 | lldb::offset_t offset = 0; |
240 | 0 | const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0); |
241 | 0 | uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); |
242 | 0 | register_write_successful = |
243 | 0 | reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value); |
244 | 0 | } else if ((type_flags & eTypeIsScalar) || |
245 | 0 | (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' |
246 | 0 | { |
247 | 0 | lldb::offset_t offset = 0; |
248 | 0 | const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0); |
249 | |
|
250 | 0 | if (type_flags & eTypeIsInteger) // 'Integral' except enum |
251 | 0 | { |
252 | 0 | switch (num_bytes) { |
253 | 0 | default: |
254 | 0 | break; |
255 | 0 | case 16: |
256 | | // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to |
257 | | // handle it |
258 | 0 | break; |
259 | 0 | case 8: { |
260 | 0 | uint32_t raw_value_low = data.GetMaxU32(&offset, 4); |
261 | 0 | const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0); |
262 | 0 | uint32_t raw_value_high = data.GetMaxU32(&offset, num_bytes - offset); |
263 | 0 | register_write_successful = |
264 | 0 | (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value_low) && |
265 | 0 | reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value_high)); |
266 | 0 | break; |
267 | 0 | } |
268 | 0 | case 4: |
269 | 0 | case 2: |
270 | 0 | case 1: { |
271 | 0 | uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); |
272 | 0 | register_write_successful = |
273 | 0 | reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value); |
274 | 0 | break; |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } else if (type_flags & eTypeIsEnumeration) // handles enum |
278 | 0 | { |
279 | 0 | uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); |
280 | 0 | register_write_successful = |
281 | 0 | reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value); |
282 | 0 | } else if (type_flags & eTypeIsFloat) // 'Floating Point' |
283 | 0 | { |
284 | 0 | RegisterValue st0_value, fstat_value, ftag_value; |
285 | 0 | const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0); |
286 | 0 | const RegisterInfo *fstat_info = |
287 | 0 | reg_ctx->GetRegisterInfoByName("fstat", 0); |
288 | 0 | const RegisterInfo *ftag_info = reg_ctx->GetRegisterInfoByName("ftag", 0); |
289 | | |
290 | | /* According to Page 3-12 of document |
291 | | System V Application Binary Interface, Intel386 Architecture Processor |
292 | | Supplement, Fourth Edition |
293 | | To return Floating Point values, all st% registers except st0 should be |
294 | | empty after exiting from |
295 | | a function. This requires setting fstat and ftag registers to specific |
296 | | values. |
297 | | fstat: The TOP field of fstat should be set to a value [0,7]. ABI doesn't |
298 | | specify the specific |
299 | | value of TOP in case of function return. Hence, we set the TOP field to 7 |
300 | | by our choice. */ |
301 | 0 | uint32_t value_fstat_u32 = 0x00003800; |
302 | | |
303 | | /* ftag: Implication of setting TOP to 7 and indicating all st% registers |
304 | | empty except st0 is to set |
305 | | 7th bit of 4th byte of FXSAVE area to 1 and all other bits of this byte to |
306 | | 0. This is in accordance |
307 | | with the document Intel 64 and IA-32 Architectures Software Developer's |
308 | | Manual, January 2015 */ |
309 | 0 | uint32_t value_ftag_u32 = 0x00000080; |
310 | |
|
311 | 0 | if (num_bytes <= 12) // handles float, double, long double, __float80 |
312 | 0 | { |
313 | 0 | long double value_long_dbl = 0.0; |
314 | 0 | if (num_bytes == 4) |
315 | 0 | value_long_dbl = data.GetFloat(&offset); |
316 | 0 | else if (num_bytes == 8) |
317 | 0 | value_long_dbl = data.GetDouble(&offset); |
318 | 0 | else if (num_bytes == 12) |
319 | 0 | value_long_dbl = data.GetLongDouble(&offset); |
320 | 0 | else { |
321 | 0 | error.SetErrorString("Invalid number of bytes for this return type"); |
322 | 0 | return error; |
323 | 0 | } |
324 | 0 | st0_value.SetLongDouble(value_long_dbl); |
325 | 0 | fstat_value.SetUInt32(value_fstat_u32); |
326 | 0 | ftag_value.SetUInt32(value_ftag_u32); |
327 | 0 | register_write_successful = |
328 | 0 | reg_ctx->WriteRegister(st0_info, st0_value) && |
329 | 0 | reg_ctx->WriteRegister(fstat_info, fstat_value) && |
330 | 0 | reg_ctx->WriteRegister(ftag_info, ftag_value); |
331 | 0 | } else if (num_bytes == 16) // handles __float128 |
332 | 0 | { |
333 | 0 | error.SetErrorString("Implementation is missing for this clang type."); |
334 | 0 | } |
335 | 0 | } else { |
336 | | // Neither 'Integral' nor 'Floating Point'. If flow reaches here then |
337 | | // check type_flags. This type_flags is not a valid type. |
338 | 0 | error.SetErrorString("Invalid clang type"); |
339 | 0 | } |
340 | 0 | } else { |
341 | | /* 'Complex Floating Point', 'Packed', 'Decimal Floating Point' and |
342 | | 'Aggregate' data types |
343 | | are yet to be implemented */ |
344 | 0 | error.SetErrorString("Currently only Integral and Floating Point clang " |
345 | 0 | "types are supported."); |
346 | 0 | } |
347 | 0 | if (!register_write_successful) |
348 | 0 | error.SetErrorString("Register writing failed"); |
349 | 0 | return error; |
350 | 0 | } |
351 | | |
352 | | ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( |
353 | 0 | Thread &thread, CompilerType &return_compiler_type) const { |
354 | 0 | ValueObjectSP return_valobj_sp; |
355 | 0 | Value value; |
356 | |
|
357 | 0 | if (!return_compiler_type) |
358 | 0 | return return_valobj_sp; |
359 | | |
360 | 0 | value.SetCompilerType(return_compiler_type); |
361 | |
|
362 | 0 | RegisterContext *reg_ctx = thread.GetRegisterContext().get(); |
363 | 0 | if (!reg_ctx) |
364 | 0 | return return_valobj_sp; |
365 | | |
366 | 0 | const uint32_t type_flags = return_compiler_type.GetTypeInfo(); |
367 | |
|
368 | 0 | unsigned eax_id = |
369 | 0 | reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; |
370 | 0 | unsigned edx_id = |
371 | 0 | reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB]; |
372 | | |
373 | | // Following "IF ELSE" block categorizes various 'Fundamental Data Types'. |
374 | | // The terminology 'Fundamental Data Types' used here is adopted from Table |
375 | | // 2.1 of the reference document (specified on top of this file) |
376 | |
|
377 | 0 | if (type_flags & eTypeIsPointer) // 'Pointer' |
378 | 0 | { |
379 | 0 | uint32_t ptr = |
380 | 0 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
381 | 0 | 0xffffffff; |
382 | 0 | value.SetValueType(Value::ValueType::Scalar); |
383 | 0 | value.GetScalar() = ptr; |
384 | 0 | return_valobj_sp = ValueObjectConstResult::Create( |
385 | 0 | thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); |
386 | 0 | } else if ((type_flags & eTypeIsScalar) || |
387 | 0 | (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' |
388 | 0 | { |
389 | 0 | value.SetValueType(Value::ValueType::Scalar); |
390 | 0 | std::optional<uint64_t> byte_size = |
391 | 0 | return_compiler_type.GetByteSize(&thread); |
392 | 0 | if (!byte_size) |
393 | 0 | return return_valobj_sp; |
394 | 0 | bool success = false; |
395 | |
|
396 | 0 | if (type_flags & eTypeIsInteger) // 'Integral' except enum |
397 | 0 | { |
398 | 0 | const bool is_signed = ((type_flags & eTypeIsSigned) != 0); |
399 | 0 | uint64_t raw_value = |
400 | 0 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
401 | 0 | 0xffffffff; |
402 | 0 | raw_value |= |
403 | 0 | (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & |
404 | 0 | 0xffffffff) |
405 | 0 | << 32; |
406 | |
|
407 | 0 | switch (*byte_size) { |
408 | 0 | default: |
409 | 0 | break; |
410 | | |
411 | 0 | case 16: |
412 | | // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to |
413 | | // handle it |
414 | 0 | break; |
415 | | |
416 | 0 | case 8: |
417 | 0 | if (is_signed) |
418 | 0 | value.GetScalar() = (int64_t)(raw_value); |
419 | 0 | else |
420 | 0 | value.GetScalar() = (uint64_t)(raw_value); |
421 | 0 | success = true; |
422 | 0 | break; |
423 | | |
424 | 0 | case 4: |
425 | 0 | if (is_signed) |
426 | 0 | value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); |
427 | 0 | else |
428 | 0 | value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); |
429 | 0 | success = true; |
430 | 0 | break; |
431 | | |
432 | 0 | case 2: |
433 | 0 | if (is_signed) |
434 | 0 | value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); |
435 | 0 | else |
436 | 0 | value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); |
437 | 0 | success = true; |
438 | 0 | break; |
439 | | |
440 | 0 | case 1: |
441 | 0 | if (is_signed) |
442 | 0 | value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); |
443 | 0 | else |
444 | 0 | value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); |
445 | 0 | success = true; |
446 | 0 | break; |
447 | 0 | } |
448 | | |
449 | 0 | if (success) |
450 | 0 | return_valobj_sp = ValueObjectConstResult::Create( |
451 | 0 | thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); |
452 | 0 | } else if (type_flags & eTypeIsEnumeration) // handles enum |
453 | 0 | { |
454 | 0 | uint32_t enm = |
455 | 0 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
456 | 0 | 0xffffffff; |
457 | 0 | value.SetValueType(Value::ValueType::Scalar); |
458 | 0 | value.GetScalar() = enm; |
459 | 0 | return_valobj_sp = ValueObjectConstResult::Create( |
460 | 0 | thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); |
461 | 0 | } else if (type_flags & eTypeIsFloat) // 'Floating Point' |
462 | 0 | { |
463 | 0 | if (*byte_size <= 12) // handles float, double, long double, __float80 |
464 | 0 | { |
465 | 0 | const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0); |
466 | 0 | RegisterValue st0_value; |
467 | |
|
468 | 0 | if (reg_ctx->ReadRegister(st0_info, st0_value)) { |
469 | 0 | DataExtractor data; |
470 | 0 | if (st0_value.GetData(data)) { |
471 | 0 | lldb::offset_t offset = 0; |
472 | 0 | long double value_long_double = data.GetLongDouble(&offset); |
473 | | |
474 | | // float is 4 bytes. |
475 | 0 | if (*byte_size == 4) { |
476 | 0 | float value_float = (float)value_long_double; |
477 | 0 | value.GetScalar() = value_float; |
478 | 0 | success = true; |
479 | 0 | } else if (*byte_size == 8) { |
480 | | // double is 8 bytes |
481 | | // On Android Platform: long double is also 8 bytes It will be |
482 | | // handled here only. |
483 | 0 | double value_double = (double)value_long_double; |
484 | 0 | value.GetScalar() = value_double; |
485 | 0 | success = true; |
486 | 0 | } else if (*byte_size == 12) { |
487 | | // long double and __float80 are 12 bytes on i386. |
488 | 0 | value.GetScalar() = value_long_double; |
489 | 0 | success = true; |
490 | 0 | } |
491 | 0 | } |
492 | 0 | } |
493 | |
|
494 | 0 | if (success) |
495 | 0 | return_valobj_sp = ValueObjectConstResult::Create( |
496 | 0 | thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); |
497 | 0 | } else if (*byte_size == 16) // handles __float128 |
498 | 0 | { |
499 | 0 | lldb::addr_t storage_addr = (uint32_t)( |
500 | 0 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
501 | 0 | 0xffffffff); |
502 | 0 | return_valobj_sp = ValueObjectMemory::Create( |
503 | 0 | &thread, "", Address(storage_addr, nullptr), return_compiler_type); |
504 | 0 | } |
505 | 0 | } else // Neither 'Integral' nor 'Floating Point' |
506 | 0 | { |
507 | | // If flow reaches here then check type_flags This type_flags is |
508 | | // unhandled |
509 | 0 | } |
510 | 0 | } else if (type_flags & eTypeIsComplex) // 'Complex Floating Point' |
511 | 0 | { |
512 | | // ToDo: Yet to be implemented |
513 | 0 | } else if (type_flags & eTypeIsVector) // 'Packed' |
514 | 0 | { |
515 | 0 | std::optional<uint64_t> byte_size = |
516 | 0 | return_compiler_type.GetByteSize(&thread); |
517 | 0 | if (byte_size && *byte_size > 0) { |
518 | 0 | const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); |
519 | 0 | if (vec_reg == nullptr) |
520 | 0 | vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); |
521 | |
|
522 | 0 | if (vec_reg) { |
523 | 0 | if (*byte_size <= vec_reg->byte_size) { |
524 | 0 | ProcessSP process_sp(thread.GetProcess()); |
525 | 0 | if (process_sp) { |
526 | 0 | std::unique_ptr<DataBufferHeap> heap_data_up( |
527 | 0 | new DataBufferHeap(*byte_size, 0)); |
528 | 0 | const ByteOrder byte_order = process_sp->GetByteOrder(); |
529 | 0 | RegisterValue reg_value; |
530 | 0 | if (reg_ctx->ReadRegister(vec_reg, reg_value)) { |
531 | 0 | Status error; |
532 | 0 | if (reg_value.GetAsMemoryData(*vec_reg, heap_data_up->GetBytes(), |
533 | 0 | heap_data_up->GetByteSize(), |
534 | 0 | byte_order, error)) { |
535 | 0 | DataExtractor data(DataBufferSP(heap_data_up.release()), |
536 | 0 | byte_order, |
537 | 0 | process_sp->GetTarget() |
538 | 0 | .GetArchitecture() |
539 | 0 | .GetAddressByteSize()); |
540 | 0 | return_valobj_sp = ValueObjectConstResult::Create( |
541 | 0 | &thread, return_compiler_type, ConstString(""), data); |
542 | 0 | } |
543 | 0 | } |
544 | 0 | } |
545 | 0 | } else if (*byte_size <= vec_reg->byte_size * 2) { |
546 | 0 | const RegisterInfo *vec_reg2 = |
547 | 0 | reg_ctx->GetRegisterInfoByName("xmm1", 0); |
548 | 0 | if (vec_reg2) { |
549 | 0 | ProcessSP process_sp(thread.GetProcess()); |
550 | 0 | if (process_sp) { |
551 | 0 | std::unique_ptr<DataBufferHeap> heap_data_up( |
552 | 0 | new DataBufferHeap(*byte_size, 0)); |
553 | 0 | const ByteOrder byte_order = process_sp->GetByteOrder(); |
554 | 0 | RegisterValue reg_value; |
555 | 0 | RegisterValue reg_value2; |
556 | 0 | if (reg_ctx->ReadRegister(vec_reg, reg_value) && |
557 | 0 | reg_ctx->ReadRegister(vec_reg2, reg_value2)) { |
558 | |
|
559 | 0 | Status error; |
560 | 0 | if (reg_value.GetAsMemoryData( |
561 | 0 | *vec_reg, heap_data_up->GetBytes(), vec_reg->byte_size, |
562 | 0 | byte_order, error) && |
563 | 0 | reg_value2.GetAsMemoryData( |
564 | 0 | *vec_reg2, |
565 | 0 | heap_data_up->GetBytes() + vec_reg->byte_size, |
566 | 0 | heap_data_up->GetByteSize() - vec_reg->byte_size, |
567 | 0 | byte_order, error)) { |
568 | 0 | DataExtractor data(DataBufferSP(heap_data_up.release()), |
569 | 0 | byte_order, |
570 | 0 | process_sp->GetTarget() |
571 | 0 | .GetArchitecture() |
572 | 0 | .GetAddressByteSize()); |
573 | 0 | return_valobj_sp = ValueObjectConstResult::Create( |
574 | 0 | &thread, return_compiler_type, ConstString(""), data); |
575 | 0 | } |
576 | 0 | } |
577 | 0 | } |
578 | 0 | } |
579 | 0 | } |
580 | 0 | } |
581 | 0 | } |
582 | 0 | } else // 'Decimal Floating Point' |
583 | 0 | { |
584 | | // ToDo: Yet to be implemented |
585 | 0 | } |
586 | 0 | return return_valobj_sp; |
587 | 0 | } |
588 | | |
589 | | ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl( |
590 | 0 | Thread &thread, CompilerType &return_compiler_type) const { |
591 | 0 | ValueObjectSP return_valobj_sp; |
592 | |
|
593 | 0 | if (!return_compiler_type) |
594 | 0 | return return_valobj_sp; |
595 | | |
596 | 0 | ExecutionContext exe_ctx(thread.shared_from_this()); |
597 | 0 | return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type); |
598 | 0 | if (return_valobj_sp) |
599 | 0 | return return_valobj_sp; |
600 | | |
601 | 0 | RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); |
602 | 0 | if (!reg_ctx_sp) |
603 | 0 | return return_valobj_sp; |
604 | | |
605 | 0 | if (return_compiler_type.IsAggregateType()) { |
606 | 0 | unsigned eax_id = |
607 | 0 | reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; |
608 | 0 | lldb::addr_t storage_addr = (uint32_t)( |
609 | 0 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
610 | 0 | 0xffffffff); |
611 | 0 | return_valobj_sp = ValueObjectMemory::Create( |
612 | 0 | &thread, "", Address(storage_addr, nullptr), return_compiler_type); |
613 | 0 | } |
614 | |
|
615 | 0 | return return_valobj_sp; |
616 | 0 | } |
617 | | |
618 | | // This defines CFA as esp+4 |
619 | | // The saved pc is at CFA-4 (i.e. esp+0) |
620 | | // The saved esp is CFA+0 |
621 | | |
622 | 34 | bool ABISysV_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { |
623 | 34 | unwind_plan.Clear(); |
624 | 34 | unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
625 | | |
626 | 34 | uint32_t sp_reg_num = dwarf_esp; |
627 | 34 | uint32_t pc_reg_num = dwarf_eip; |
628 | | |
629 | 34 | UnwindPlan::RowSP row(new UnwindPlan::Row); |
630 | 34 | row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4); |
631 | 34 | row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false); |
632 | 34 | row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); |
633 | 34 | unwind_plan.AppendRow(row); |
634 | 34 | unwind_plan.SetSourceName("i386 at-func-entry default"); |
635 | 34 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
636 | 34 | return true; |
637 | 34 | } |
638 | | |
639 | | // This defines CFA as ebp+8 |
640 | | // The saved pc is at CFA-4 (i.e. ebp+4) |
641 | | // The saved ebp is at CFA-8 (i.e. ebp+0) |
642 | | // The saved esp is CFA+0 |
643 | | |
644 | 111 | bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { |
645 | 111 | unwind_plan.Clear(); |
646 | 111 | unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
647 | | |
648 | 111 | uint32_t fp_reg_num = dwarf_ebp; |
649 | 111 | uint32_t sp_reg_num = dwarf_esp; |
650 | 111 | uint32_t pc_reg_num = dwarf_eip; |
651 | | |
652 | 111 | UnwindPlan::RowSP row(new UnwindPlan::Row); |
653 | 111 | const int32_t ptr_size = 4; |
654 | | |
655 | 111 | row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); |
656 | 111 | row->SetOffset(0); |
657 | 111 | row->SetUnspecifiedRegistersAreUndefined(true); |
658 | | |
659 | 111 | row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); |
660 | 111 | row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); |
661 | 111 | row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); |
662 | | |
663 | 111 | unwind_plan.AppendRow(row); |
664 | 111 | unwind_plan.SetSourceName("i386 default unwind plan"); |
665 | 111 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
666 | 111 | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); |
667 | 111 | unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); |
668 | 111 | return true; |
669 | 111 | } |
670 | | |
671 | | // According to "Register Usage" in reference document (specified on top of |
672 | | // this source file) ebx, ebp, esi, edi and esp registers are preserved i.e. |
673 | | // non-volatile i.e. callee-saved on i386 |
674 | 9 | bool ABISysV_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { |
675 | 9 | if (!reg_info) |
676 | 0 | return false; |
677 | | |
678 | | // Saved registers are ebx, ebp, esi, edi, esp, eip |
679 | 9 | const char *name = reg_info->name; |
680 | 9 | if (name[0] == 'e') { |
681 | 9 | switch (name[1]) { |
682 | 9 | case 'b': |
683 | 9 | if (name[2] == 'x' || name[2] == 'p') |
684 | 9 | return name[3] == '\0'; |
685 | 0 | break; |
686 | 0 | case 'd': |
687 | 0 | if (name[2] == 'i') |
688 | 0 | return name[3] == '\0'; |
689 | 0 | break; |
690 | 0 | case 'i': |
691 | 0 | if (name[2] == 'p') |
692 | 0 | return name[3] == '\0'; |
693 | 0 | break; |
694 | 0 | case 's': |
695 | 0 | if (name[2] == 'i' || name[2] == 'p') |
696 | 0 | return name[3] == '\0'; |
697 | 0 | break; |
698 | 9 | } |
699 | 9 | } |
700 | | |
701 | 0 | if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp |
702 | 0 | return true; |
703 | 0 | if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp |
704 | 0 | return true; |
705 | 0 | if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc |
706 | 0 | return true; |
707 | | |
708 | 0 | return false; |
709 | 0 | } |
710 | | |
711 | 3.92k | void ABISysV_i386::Initialize() { |
712 | 3.92k | PluginManager::RegisterPlugin( |
713 | 3.92k | GetPluginNameStatic(), "System V ABI for i386 targets", CreateInstance); |
714 | 3.92k | } |
715 | | |
716 | 3.92k | void ABISysV_i386::Terminate() { |
717 | 3.92k | PluginManager::UnregisterPlugin(CreateInstance); |
718 | 3.92k | } |