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