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 | 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 = compiler_type.GetBitSize(exe_scope: &thread); |
186 | if (bit_size) { |
187 | bool is_signed; |
188 | if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { |
189 | ReadIntegerArgument(scalar&: value->GetScalar(), bit_width: *bit_size, is_signed, |
190 | process: thread.GetProcess().get(), current_stack_argument); |
191 | } else if (compiler_type.IsPointerType()) { |
192 | ReadIntegerArgument(scalar&: value->GetScalar(), bit_width: *bit_size, is_signed: false, |
193 | process: thread.GetProcess().get(), current_stack_argument); |
194 | } |
195 | } |
196 | } |
197 | return true; |
198 | } |
199 | |
200 | Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, |
201 | lldb::ValueObjectSP &new_value_sp) { |
202 | Status error; |
203 | if (!new_value_sp) { |
204 | error.SetErrorString("Empty value object for return value." ); |
205 | return error; |
206 | } |
207 | |
208 | CompilerType compiler_type = new_value_sp->GetCompilerType(); |
209 | if (!compiler_type) { |
210 | error.SetErrorString("Null clang type for return value." ); |
211 | return error; |
212 | } |
213 | |
214 | const uint32_t type_flags = compiler_type.GetTypeInfo(); |
215 | Thread *thread = frame_sp->GetThread().get(); |
216 | RegisterContext *reg_ctx = thread->GetRegisterContext().get(); |
217 | DataExtractor data; |
218 | Status data_error; |
219 | size_t num_bytes = new_value_sp->GetData(data, error&: data_error); |
220 | bool register_write_successful = true; |
221 | |
222 | if (data_error.Fail()) { |
223 | error.SetErrorStringWithFormat( |
224 | "Couldn't convert return value to raw data: %s" , |
225 | data_error.AsCString()); |
226 | return error; |
227 | } |
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 | if (type_flags & eTypeIsPointer) // 'Pointer' |
234 | { |
235 | if (num_bytes != sizeof(uint32_t)) { |
236 | error.SetErrorString("Pointer to be returned is not 4 bytes wide" ); |
237 | return error; |
238 | } |
239 | lldb::offset_t offset = 0; |
240 | const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName(reg_name: "eax" , start_idx: 0); |
241 | uint32_t raw_value = data.GetMaxU32(offset_ptr: &offset, byte_size: num_bytes); |
242 | register_write_successful = |
243 | reg_ctx->WriteRegisterFromUnsigned(reg_info: eax_info, uval: raw_value); |
244 | } else if ((type_flags & eTypeIsScalar) || |
245 | (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' |
246 | { |
247 | lldb::offset_t offset = 0; |
248 | const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName(reg_name: "eax" , start_idx: 0); |
249 | |
250 | if (type_flags & eTypeIsInteger) // 'Integral' except enum |
251 | { |
252 | switch (num_bytes) { |
253 | default: |
254 | break; |
255 | case 16: |
256 | // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to |
257 | // handle it |
258 | break; |
259 | case 8: { |
260 | uint32_t raw_value_low = data.GetMaxU32(offset_ptr: &offset, byte_size: 4); |
261 | const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName(reg_name: "edx" , start_idx: 0); |
262 | uint32_t raw_value_high = data.GetMaxU32(offset_ptr: &offset, byte_size: num_bytes - offset); |
263 | register_write_successful = |
264 | (reg_ctx->WriteRegisterFromUnsigned(reg_info: eax_info, uval: raw_value_low) && |
265 | reg_ctx->WriteRegisterFromUnsigned(reg_info: edx_info, uval: raw_value_high)); |
266 | break; |
267 | } |
268 | case 4: |
269 | case 2: |
270 | case 1: { |
271 | uint32_t raw_value = data.GetMaxU32(offset_ptr: &offset, byte_size: num_bytes); |
272 | register_write_successful = |
273 | reg_ctx->WriteRegisterFromUnsigned(reg_info: eax_info, uval: raw_value); |
274 | break; |
275 | } |
276 | } |
277 | } else if (type_flags & eTypeIsEnumeration) // handles enum |
278 | { |
279 | uint32_t raw_value = data.GetMaxU32(offset_ptr: &offset, byte_size: num_bytes); |
280 | register_write_successful = |
281 | reg_ctx->WriteRegisterFromUnsigned(reg_info: eax_info, uval: raw_value); |
282 | } else if (type_flags & eTypeIsFloat) // 'Floating Point' |
283 | { |
284 | RegisterValue st0_value, fstat_value, ftag_value; |
285 | const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName(reg_name: "st0" , start_idx: 0); |
286 | const RegisterInfo *fstat_info = |
287 | reg_ctx->GetRegisterInfoByName(reg_name: "fstat" , start_idx: 0); |
288 | const RegisterInfo *ftag_info = reg_ctx->GetRegisterInfoByName(reg_name: "ftag" , start_idx: 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 | 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 | uint32_t value_ftag_u32 = 0x00000080; |
310 | |
311 | if (num_bytes <= 12) // handles float, double, long double, __float80 |
312 | { |
313 | long double value_long_dbl = 0.0; |
314 | if (num_bytes == 4) |
315 | value_long_dbl = data.GetFloat(offset_ptr: &offset); |
316 | else if (num_bytes == 8) |
317 | value_long_dbl = data.GetDouble(offset_ptr: &offset); |
318 | else if (num_bytes == 12) |
319 | value_long_dbl = data.GetLongDouble(offset_ptr: &offset); |
320 | else { |
321 | error.SetErrorString("Invalid number of bytes for this return type" ); |
322 | return error; |
323 | } |
324 | st0_value.SetLongDouble(value_long_dbl); |
325 | fstat_value.SetUInt32(uint: value_fstat_u32); |
326 | ftag_value.SetUInt32(uint: value_ftag_u32); |
327 | register_write_successful = |
328 | reg_ctx->WriteRegister(reg_info: st0_info, reg_value: st0_value) && |
329 | reg_ctx->WriteRegister(reg_info: fstat_info, reg_value: fstat_value) && |
330 | reg_ctx->WriteRegister(reg_info: ftag_info, reg_value: ftag_value); |
331 | } else if (num_bytes == 16) // handles __float128 |
332 | { |
333 | error.SetErrorString("Implementation is missing for this clang type." ); |
334 | } |
335 | } 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 | error.SetErrorString("Invalid clang type" ); |
339 | } |
340 | } else { |
341 | /* 'Complex Floating Point', 'Packed', 'Decimal Floating Point' and |
342 | 'Aggregate' data types |
343 | are yet to be implemented */ |
344 | error.SetErrorString("Currently only Integral and Floating Point clang " |
345 | "types are supported." ); |
346 | } |
347 | if (!register_write_successful) |
348 | error.SetErrorString("Register writing failed" ); |
349 | return error; |
350 | } |
351 | |
352 | ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( |
353 | Thread &thread, CompilerType &return_compiler_type) const { |
354 | ValueObjectSP return_valobj_sp; |
355 | Value value; |
356 | |
357 | if (!return_compiler_type) |
358 | return return_valobj_sp; |
359 | |
360 | value.SetCompilerType(return_compiler_type); |
361 | |
362 | RegisterContext *reg_ctx = thread.GetRegisterContext().get(); |
363 | if (!reg_ctx) |
364 | return return_valobj_sp; |
365 | |
366 | const uint32_t type_flags = return_compiler_type.GetTypeInfo(); |
367 | |
368 | unsigned eax_id = |
369 | reg_ctx->GetRegisterInfoByName(reg_name: "eax" , start_idx: 0)->kinds[eRegisterKindLLDB]; |
370 | unsigned edx_id = |
371 | reg_ctx->GetRegisterInfoByName(reg_name: "edx" , start_idx: 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 | if (type_flags & eTypeIsPointer) // 'Pointer' |
378 | { |
379 | uint32_t ptr = |
380 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg: eax_id, fail_value: 0) & |
381 | 0xffffffff; |
382 | value.SetValueType(Value::ValueType::Scalar); |
383 | value.GetScalar() = ptr; |
384 | return_valobj_sp = ValueObjectConstResult::Create( |
385 | exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString("" )); |
386 | } else if ((type_flags & eTypeIsScalar) || |
387 | (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' |
388 | { |
389 | value.SetValueType(Value::ValueType::Scalar); |
390 | std::optional<uint64_t> byte_size = |
391 | return_compiler_type.GetByteSize(exe_scope: &thread); |
392 | if (!byte_size) |
393 | return return_valobj_sp; |
394 | bool success = false; |
395 | |
396 | if (type_flags & eTypeIsInteger) // 'Integral' except enum |
397 | { |
398 | const bool is_signed = ((type_flags & eTypeIsSigned) != 0); |
399 | uint64_t raw_value = |
400 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg: eax_id, fail_value: 0) & |
401 | 0xffffffff; |
402 | raw_value |= |
403 | (thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg: edx_id, fail_value: 0) & |
404 | 0xffffffff) |
405 | << 32; |
406 | |
407 | switch (*byte_size) { |
408 | default: |
409 | break; |
410 | |
411 | case 16: |
412 | // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to |
413 | // handle it |
414 | break; |
415 | |
416 | case 8: |
417 | if (is_signed) |
418 | value.GetScalar() = (int64_t)(raw_value); |
419 | else |
420 | value.GetScalar() = (uint64_t)(raw_value); |
421 | success = true; |
422 | break; |
423 | |
424 | case 4: |
425 | if (is_signed) |
426 | value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); |
427 | else |
428 | value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); |
429 | success = true; |
430 | break; |
431 | |
432 | case 2: |
433 | if (is_signed) |
434 | value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); |
435 | else |
436 | value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); |
437 | success = true; |
438 | break; |
439 | |
440 | case 1: |
441 | if (is_signed) |
442 | value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); |
443 | else |
444 | value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); |
445 | success = true; |
446 | break; |
447 | } |
448 | |
449 | if (success) |
450 | return_valobj_sp = ValueObjectConstResult::Create( |
451 | exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString("" )); |
452 | } else if (type_flags & eTypeIsEnumeration) // handles enum |
453 | { |
454 | uint32_t enm = |
455 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg: eax_id, fail_value: 0) & |
456 | 0xffffffff; |
457 | value.SetValueType(Value::ValueType::Scalar); |
458 | value.GetScalar() = enm; |
459 | return_valobj_sp = ValueObjectConstResult::Create( |
460 | exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString("" )); |
461 | } else if (type_flags & eTypeIsFloat) // 'Floating Point' |
462 | { |
463 | if (*byte_size <= 12) // handles float, double, long double, __float80 |
464 | { |
465 | const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName(reg_name: "st0" , start_idx: 0); |
466 | RegisterValue st0_value; |
467 | |
468 | if (reg_ctx->ReadRegister(reg_info: st0_info, reg_value&: st0_value)) { |
469 | DataExtractor data; |
470 | if (st0_value.GetData(data)) { |
471 | lldb::offset_t offset = 0; |
472 | long double value_long_double = data.GetLongDouble(offset_ptr: &offset); |
473 | |
474 | // float is 4 bytes. |
475 | if (*byte_size == 4) { |
476 | float value_float = (float)value_long_double; |
477 | value.GetScalar() = value_float; |
478 | success = true; |
479 | } 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 | double value_double = (double)value_long_double; |
484 | value.GetScalar() = value_double; |
485 | success = true; |
486 | } else if (*byte_size == 12) { |
487 | // long double and __float80 are 12 bytes on i386. |
488 | value.GetScalar() = value_long_double; |
489 | success = true; |
490 | } |
491 | } |
492 | } |
493 | |
494 | if (success) |
495 | return_valobj_sp = ValueObjectConstResult::Create( |
496 | exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString("" )); |
497 | } else if (*byte_size == 16) // handles __float128 |
498 | { |
499 | lldb::addr_t storage_addr = (uint32_t)( |
500 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg: eax_id, fail_value: 0) & |
501 | 0xffffffff); |
502 | return_valobj_sp = ValueObjectMemory::Create( |
503 | exe_scope: &thread, name: "" , address: Address(storage_addr, nullptr), ast_type: return_compiler_type); |
504 | } |
505 | } else // Neither 'Integral' nor 'Floating Point' |
506 | { |
507 | // If flow reaches here then check type_flags This type_flags is |
508 | // unhandled |
509 | } |
510 | } else if (type_flags & eTypeIsComplex) // 'Complex Floating Point' |
511 | { |
512 | // ToDo: Yet to be implemented |
513 | } else if (type_flags & eTypeIsVector) // 'Packed' |
514 | { |
515 | std::optional<uint64_t> byte_size = |
516 | return_compiler_type.GetByteSize(exe_scope: &thread); |
517 | if (byte_size && *byte_size > 0) { |
518 | const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName(reg_name: "xmm0" , start_idx: 0); |
519 | if (vec_reg == nullptr) |
520 | vec_reg = reg_ctx->GetRegisterInfoByName(reg_name: "mm0" , start_idx: 0); |
521 | |
522 | if (vec_reg) { |
523 | if (*byte_size <= vec_reg->byte_size) { |
524 | ProcessSP process_sp(thread.GetProcess()); |
525 | if (process_sp) { |
526 | std::unique_ptr<DataBufferHeap> heap_data_up( |
527 | new DataBufferHeap(*byte_size, 0)); |
528 | const ByteOrder byte_order = process_sp->GetByteOrder(); |
529 | RegisterValue reg_value; |
530 | if (reg_ctx->ReadRegister(reg_info: vec_reg, reg_value)) { |
531 | Status error; |
532 | if (reg_value.GetAsMemoryData(reg_info: *vec_reg, dst: heap_data_up->GetBytes(), |
533 | dst_len: heap_data_up->GetByteSize(), |
534 | dst_byte_order: byte_order, error)) { |
535 | DataExtractor data(DataBufferSP(heap_data_up.release()), |
536 | byte_order, |
537 | process_sp->GetTarget() |
538 | .GetArchitecture() |
539 | .GetAddressByteSize()); |
540 | return_valobj_sp = ValueObjectConstResult::Create( |
541 | exe_scope: &thread, compiler_type: return_compiler_type, name: ConstString("" ), data); |
542 | } |
543 | } |
544 | } |
545 | } else if (*byte_size <= vec_reg->byte_size * 2) { |
546 | const RegisterInfo *vec_reg2 = |
547 | reg_ctx->GetRegisterInfoByName(reg_name: "xmm1" , start_idx: 0); |
548 | if (vec_reg2) { |
549 | ProcessSP process_sp(thread.GetProcess()); |
550 | if (process_sp) { |
551 | std::unique_ptr<DataBufferHeap> heap_data_up( |
552 | new DataBufferHeap(*byte_size, 0)); |
553 | const ByteOrder byte_order = process_sp->GetByteOrder(); |
554 | RegisterValue reg_value; |
555 | RegisterValue reg_value2; |
556 | if (reg_ctx->ReadRegister(reg_info: vec_reg, reg_value) && |
557 | reg_ctx->ReadRegister(reg_info: vec_reg2, reg_value&: reg_value2)) { |
558 | |
559 | Status error; |
560 | if (reg_value.GetAsMemoryData( |
561 | reg_info: *vec_reg, dst: heap_data_up->GetBytes(), dst_len: vec_reg->byte_size, |
562 | dst_byte_order: byte_order, error) && |
563 | reg_value2.GetAsMemoryData( |
564 | reg_info: *vec_reg2, |
565 | dst: heap_data_up->GetBytes() + vec_reg->byte_size, |
566 | dst_len: heap_data_up->GetByteSize() - vec_reg->byte_size, |
567 | dst_byte_order: byte_order, error)) { |
568 | DataExtractor data(DataBufferSP(heap_data_up.release()), |
569 | byte_order, |
570 | process_sp->GetTarget() |
571 | .GetArchitecture() |
572 | .GetAddressByteSize()); |
573 | return_valobj_sp = ValueObjectConstResult::Create( |
574 | exe_scope: &thread, compiler_type: return_compiler_type, name: ConstString("" ), data); |
575 | } |
576 | } |
577 | } |
578 | } |
579 | } |
580 | } |
581 | } |
582 | } else // 'Decimal Floating Point' |
583 | { |
584 | // ToDo: Yet to be implemented |
585 | } |
586 | return return_valobj_sp; |
587 | } |
588 | |
589 | ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl( |
590 | Thread &thread, CompilerType &return_compiler_type) const { |
591 | ValueObjectSP return_valobj_sp; |
592 | |
593 | if (!return_compiler_type) |
594 | return return_valobj_sp; |
595 | |
596 | ExecutionContext exe_ctx(thread.shared_from_this()); |
597 | return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type); |
598 | if (return_valobj_sp) |
599 | return return_valobj_sp; |
600 | |
601 | RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); |
602 | if (!reg_ctx_sp) |
603 | return return_valobj_sp; |
604 | |
605 | if (return_compiler_type.IsAggregateType()) { |
606 | unsigned eax_id = |
607 | reg_ctx_sp->GetRegisterInfoByName(reg_name: "eax" , start_idx: 0)->kinds[eRegisterKindLLDB]; |
608 | lldb::addr_t storage_addr = (uint32_t)( |
609 | thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg: eax_id, fail_value: 0) & |
610 | 0xffffffff); |
611 | return_valobj_sp = ValueObjectMemory::Create( |
612 | exe_scope: &thread, name: "" , address: Address(storage_addr, nullptr), ast_type: return_compiler_type); |
613 | } |
614 | |
615 | return return_valobj_sp; |
616 | } |
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 | bool ABISysV_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { |
623 | unwind_plan.Clear(); |
624 | unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
625 | |
626 | uint32_t sp_reg_num = dwarf_esp; |
627 | uint32_t pc_reg_num = dwarf_eip; |
628 | |
629 | UnwindPlan::RowSP row(new UnwindPlan::Row); |
630 | row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: sp_reg_num, offset: 4); |
631 | row->SetRegisterLocationToAtCFAPlusOffset(reg_num: pc_reg_num, offset: -4, can_replace: false); |
632 | row->SetRegisterLocationToIsCFAPlusOffset(reg_num: sp_reg_num, offset: 0, can_replace: true); |
633 | unwind_plan.AppendRow(row_sp: row); |
634 | unwind_plan.SetSourceName("i386 at-func-entry default" ); |
635 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
636 | return true; |
637 | } |
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 | bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { |
645 | unwind_plan.Clear(); |
646 | unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
647 | |
648 | uint32_t fp_reg_num = dwarf_ebp; |
649 | uint32_t sp_reg_num = dwarf_esp; |
650 | uint32_t pc_reg_num = dwarf_eip; |
651 | |
652 | UnwindPlan::RowSP row(new UnwindPlan::Row); |
653 | const int32_t ptr_size = 4; |
654 | |
655 | row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: fp_reg_num, offset: 2 * ptr_size); |
656 | row->SetOffset(0); |
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 | unwind_plan.AppendRow(row_sp: row); |
664 | unwind_plan.SetSourceName("i386 default unwind plan" ); |
665 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
666 | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); |
667 | unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); |
668 | return true; |
669 | } |
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 | bool ABISysV_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { |
675 | if (!reg_info) |
676 | return false; |
677 | |
678 | // Saved registers are ebx, ebp, esi, edi, esp, eip |
679 | const char *name = reg_info->name; |
680 | if (name[0] == 'e') { |
681 | switch (name[1]) { |
682 | case 'b': |
683 | if (name[2] == 'x' || name[2] == 'p') |
684 | return name[3] == '\0'; |
685 | break; |
686 | case 'd': |
687 | if (name[2] == 'i') |
688 | return name[3] == '\0'; |
689 | break; |
690 | case 'i': |
691 | if (name[2] == 'p') |
692 | return name[3] == '\0'; |
693 | break; |
694 | case 's': |
695 | if (name[2] == 'i' || name[2] == 'p') |
696 | return name[3] == '\0'; |
697 | break; |
698 | } |
699 | } |
700 | |
701 | if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp |
702 | return true; |
703 | if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp |
704 | return true; |
705 | if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc |
706 | return true; |
707 | |
708 | return false; |
709 | } |
710 | |
711 | void ABISysV_i386::Initialize() { |
712 | PluginManager::RegisterPlugin( |
713 | name: GetPluginNameStatic(), description: "System V ABI for i386 targets" , create_callback: CreateInstance); |
714 | } |
715 | |
716 | void ABISysV_i386::Terminate() { |
717 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
718 | } |
719 | |