Coverage Report

Created: 2022-01-22 13:19

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- ABIMacOSX_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
9
#include "ABIMacOSX_i386.h"
10
11
#include <vector>
12
13
#include "llvm/ADT/STLExtras.h"
14
#include "llvm/ADT/Triple.h"
15
16
#include "lldb/Core/Module.h"
17
#include "lldb/Core/PluginManager.h"
18
#include "lldb/Core/ValueObjectConstResult.h"
19
#include "lldb/Symbol/UnwindPlan.h"
20
#include "lldb/Target/Process.h"
21
#include "lldb/Target/RegisterContext.h"
22
#include "lldb/Target/Target.h"
23
#include "lldb/Target/Thread.h"
24
#include "lldb/Utility/ConstString.h"
25
#include "lldb/Utility/RegisterValue.h"
26
#include "lldb/Utility/Scalar.h"
27
#include "lldb/Utility/Status.h"
28
29
using namespace lldb;
30
using namespace lldb_private;
31
32
LLDB_PLUGIN_DEFINE(ABIMacOSX_i386)
33
34
enum {
35
  dwarf_eax = 0,
36
  dwarf_ecx,
37
  dwarf_edx,
38
  dwarf_ebx,
39
  dwarf_esp,
40
  dwarf_ebp,
41
  dwarf_esi,
42
  dwarf_edi,
43
  dwarf_eip,
44
};
45
46
0
size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }
47
48
// Static Functions
49
50
ABISP
51
5.46k
ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
52
5.46k
  if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
53
5.46k
      
(32
arch.GetTriple().isMacOSX()32
||
arch.GetTriple().isiOS()32
||
54
32
       arch.GetTriple().isWatchOS())) {
55
0
    return ABISP(
56
0
        new ABIMacOSX_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));
57
0
  }
58
5.46k
  return ABISP();
59
5.46k
}
60
61
bool ABIMacOSX_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
62
                                        addr_t func_addr, addr_t return_addr,
63
0
                                        llvm::ArrayRef<addr_t> args) const {
64
0
  RegisterContext *reg_ctx = thread.GetRegisterContext().get();
65
0
  if (!reg_ctx)
66
0
    return false;
67
0
  uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
68
0
      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
69
0
  uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
70
0
      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
71
72
  // When writing a register value down to memory, the register info used to
73
  // write memory just needs to have the correct size of a 32 bit register, the
74
  // actual register it pertains to is not important, just the size needs to be
75
  // correct. Here we use "eax"...
76
0
  const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
77
0
  if (!reg_info_32)
78
0
    return false; // TODO this should actually never happen
79
80
  // Make room for the argument(s) on the stack
81
82
0
  Status error;
83
0
  RegisterValue reg_value;
84
85
  // Write any arguments onto the stack
86
0
  sp -= 4 * args.size();
87
88
  // Align the SP
89
0
  sp &= ~(16ull - 1ull); // 16-byte alignment
90
91
0
  addr_t arg_pos = sp;
92
93
0
  for (addr_t arg : args) {
94
0
    reg_value.SetUInt32(arg);
95
0
    error = reg_ctx->WriteRegisterValueToMemory(
96
0
        reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
97
0
    if (error.Fail())
98
0
      return false;
99
0
    arg_pos += 4;
100
0
  }
101
102
  // The return address is pushed onto the stack (yes after we just set the
103
  // alignment above!).
104
0
  sp -= 4;
105
0
  reg_value.SetUInt32(return_addr);
106
0
  error = reg_ctx->WriteRegisterValueToMemory(
107
0
      reg_info_32, sp, reg_info_32->byte_size, reg_value);
108
0
  if (error.Fail())
109
0
    return false;
110
111
  // %esp is set to the actual stack value.
112
113
0
  if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
114
0
    return false;
115
116
  // %eip is set to the address of the called function.
117
118
0
  if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
119
0
    return false;
120
121
0
  return true;
122
0
}
123
124
static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
125
                                bool is_signed, Process *process,
126
0
                                addr_t &current_stack_argument) {
127
128
0
  uint32_t byte_size = (bit_width + (8 - 1)) / 8;
129
0
  Status error;
130
0
  if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
131
0
                                           is_signed, scalar, error)) {
132
0
    current_stack_argument += byte_size;
133
0
    return true;
134
0
  }
135
0
  return false;
136
0
}
137
138
bool ABIMacOSX_i386::GetArgumentValues(Thread &thread,
139
0
                                       ValueList &values) const {
140
0
  unsigned int num_values = values.GetSize();
141
0
  unsigned int value_index;
142
143
  // Get the pointer to the first stack argument so we have a place to start
144
  // when reading data
145
146
0
  RegisterContext *reg_ctx = thread.GetRegisterContext().get();
147
148
0
  if (!reg_ctx)
149
0
    return false;
150
151
0
  addr_t sp = reg_ctx->GetSP(0);
152
153
0
  if (!sp)
154
0
    return false;
155
156
0
  addr_t current_stack_argument = sp + 4; // jump over return address
157
158
0
  for (value_index = 0; value_index < num_values; ++value_index) {
159
0
    Value *value = values.GetValueAtIndex(value_index);
160
161
0
    if (!value)
162
0
      return false;
163
164
    // We currently only support extracting values with Clang QualTypes. Do we
165
    // care about others?
166
0
    CompilerType compiler_type(value->GetCompilerType());
167
0
    llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
168
0
    if (bit_size) {
169
0
      bool is_signed;
170
0
      if (compiler_type.IsIntegerOrEnumerationType(is_signed))
171
0
        ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
172
0
                            thread.GetProcess().get(), current_stack_argument);
173
0
      else if (compiler_type.IsPointerType())
174
0
        ReadIntegerArgument(value->GetScalar(), *bit_size, false,
175
0
                            thread.GetProcess().get(), current_stack_argument);
176
0
    }
177
0
  }
178
179
0
  return true;
180
0
}
181
182
Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
183
0
                                            lldb::ValueObjectSP &new_value_sp) {
184
0
  Status error;
185
0
  if (!new_value_sp) {
186
0
    error.SetErrorString("Empty value object for return value.");
187
0
    return error;
188
0
  }
189
190
0
  CompilerType compiler_type = new_value_sp->GetCompilerType();
191
0
  if (!compiler_type) {
192
0
    error.SetErrorString("Null clang type for return value.");
193
0
    return error;
194
0
  }
195
196
0
  Thread *thread = frame_sp->GetThread().get();
197
198
0
  bool is_signed;
199
0
  uint32_t count;
200
0
  bool is_complex;
201
202
0
  RegisterContext *reg_ctx = thread->GetRegisterContext().get();
203
204
0
  bool set_it_simple = false;
205
0
  if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
206
0
      compiler_type.IsPointerType()) {
207
0
    DataExtractor data;
208
0
    Status data_error;
209
0
    size_t num_bytes = new_value_sp->GetData(data, data_error);
210
0
    if (data_error.Fail()) {
211
0
      error.SetErrorStringWithFormat(
212
0
          "Couldn't convert return value to raw data: %s",
213
0
          data_error.AsCString());
214
0
      return error;
215
0
    }
216
0
    lldb::offset_t offset = 0;
217
0
    if (num_bytes <= 8) {
218
0
      const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
219
0
      if (num_bytes <= 4) {
220
0
        uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
221
222
0
        if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value))
223
0
          set_it_simple = true;
224
0
      } else {
225
0
        uint32_t raw_value = data.GetMaxU32(&offset, 4);
226
227
0
        if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value)) {
228
0
          const RegisterInfo *edx_info =
229
0
              reg_ctx->GetRegisterInfoByName("edx", 0);
230
0
          uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
231
232
0
          if (reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value))
233
0
            set_it_simple = true;
234
0
        }
235
0
      }
236
0
    } else {
237
0
      error.SetErrorString("We don't support returning longer than 64 bit "
238
0
                           "integer values at present.");
239
0
    }
240
0
  } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
241
0
    if (is_complex)
242
0
      error.SetErrorString(
243
0
          "We don't support returning complex values at present");
244
0
    else
245
0
      error.SetErrorString(
246
0
          "We don't support returning float values at present");
247
0
  }
248
249
0
  if (!set_it_simple)
250
0
    error.SetErrorString(
251
0
        "We only support setting simple integer return types at present.");
252
253
0
  return error;
254
0
}
255
256
ValueObjectSP
257
ABIMacOSX_i386::GetReturnValueObjectImpl(Thread &thread,
258
0
                                         CompilerType &compiler_type) const {
259
0
  Value value;
260
0
  ValueObjectSP return_valobj_sp;
261
262
0
  if (!compiler_type)
263
0
    return return_valobj_sp;
264
265
  // value.SetContext (Value::eContextTypeClangType,
266
  // compiler_type.GetOpaqueQualType());
267
0
  value.SetCompilerType(compiler_type);
268
269
0
  RegisterContext *reg_ctx = thread.GetRegisterContext().get();
270
0
  if (!reg_ctx)
271
0
    return return_valobj_sp;
272
273
0
  bool is_signed;
274
275
0
  if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
276
0
    llvm::Optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread);
277
0
    if (!bit_width)
278
0
      return return_valobj_sp;
279
0
    unsigned eax_id =
280
0
        reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
281
0
    unsigned edx_id =
282
0
        reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
283
284
0
    switch (*bit_width) {
285
0
    default:
286
0
    case 128:
287
      // Scalar can't hold 128-bit literals, so we don't handle this
288
0
      return return_valobj_sp;
289
0
    case 64:
290
0
      uint64_t raw_value;
291
0
      raw_value =
292
0
          thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
293
0
          0xffffffff;
294
0
      raw_value |=
295
0
          (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
296
0
           0xffffffff)
297
0
          << 32;
298
0
      if (is_signed)
299
0
        value.GetScalar() = (int64_t)raw_value;
300
0
      else
301
0
        value.GetScalar() = (uint64_t)raw_value;
302
0
      break;
303
0
    case 32:
304
0
      if (is_signed)
305
0
        value.GetScalar() = (int32_t)(
306
0
            thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
307
0
            0xffffffff);
308
0
      else
309
0
        value.GetScalar() = (uint32_t)(
310
0
            thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
311
0
            0xffffffff);
312
0
      break;
313
0
    case 16:
314
0
      if (is_signed)
315
0
        value.GetScalar() = (int16_t)(
316
0
            thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
317
0
            0xffff);
318
0
      else
319
0
        value.GetScalar() = (uint16_t)(
320
0
            thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
321
0
            0xffff);
322
0
      break;
323
0
    case 8:
324
0
      if (is_signed)
325
0
        value.GetScalar() = (int8_t)(
326
0
            thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
327
0
            0xff);
328
0
      else
329
0
        value.GetScalar() = (uint8_t)(
330
0
            thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
331
0
            0xff);
332
0
      break;
333
0
    }
334
0
  } else if (compiler_type.IsPointerType()) {
335
0
    unsigned eax_id =
336
0
        reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
337
0
    uint32_t ptr =
338
0
        thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
339
0
        0xffffffff;
340
0
    value.GetScalar() = ptr;
341
0
  } else {
342
    // not handled yet
343
0
    return return_valobj_sp;
344
0
  }
345
346
  // If we get here, we have a valid Value, so make our ValueObject out of it:
347
348
0
  return_valobj_sp = ValueObjectConstResult::Create(
349
0
      thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
350
0
  return return_valobj_sp;
351
0
}
352
353
// This defines the CFA as esp+4
354
// the saved pc is at CFA-4 (i.e. esp+0)
355
// The saved esp is CFA+0
356
357
0
bool ABIMacOSX_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
358
0
  unwind_plan.Clear();
359
0
  unwind_plan.SetRegisterKind(eRegisterKindDWARF);
360
361
0
  uint32_t sp_reg_num = dwarf_esp;
362
0
  uint32_t pc_reg_num = dwarf_eip;
363
364
0
  UnwindPlan::RowSP row(new UnwindPlan::Row);
365
0
  row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
366
0
  row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
367
0
  row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
368
0
  unwind_plan.AppendRow(row);
369
0
  unwind_plan.SetSourceName("i386 at-func-entry default");
370
0
  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
371
0
  return true;
372
0
}
373
374
// This defines the CFA as ebp+8
375
// The saved pc is at CFA-4 (i.e. ebp+4)
376
// The saved ebp is at CFA-8 (i.e. ebp+0)
377
// The saved esp is CFA+0
378
379
0
bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
380
0
  unwind_plan.Clear();
381
0
  unwind_plan.SetRegisterKind(eRegisterKindDWARF);
382
383
0
  uint32_t fp_reg_num = dwarf_ebp;
384
0
  uint32_t sp_reg_num = dwarf_esp;
385
0
  uint32_t pc_reg_num = dwarf_eip;
386
387
0
  UnwindPlan::RowSP row(new UnwindPlan::Row);
388
0
  const int32_t ptr_size = 4;
389
390
0
  row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
391
0
  row->SetOffset(0);
392
0
  row->SetUnspecifiedRegistersAreUndefined(true);
393
394
0
  row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
395
0
  row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
396
0
  row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
397
398
0
  unwind_plan.AppendRow(row);
399
0
  unwind_plan.SetSourceName("i386 default unwind plan");
400
0
  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
401
0
  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
402
0
  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
403
0
  return true;
404
0
}
405
406
0
bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) {
407
0
  return !RegisterIsCalleeSaved(reg_info);
408
0
}
409
410
// v.
411
// http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130
412
// -IA-
413
// 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
414
//
415
// This document ("OS X ABI Function Call Guide", chapter "IA-32 Function
416
// Calling Conventions") says that the following registers on i386 are
417
// preserved aka non-volatile aka callee-saved:
418
//
419
// ebx, ebp, esi, edi, esp
420
421
0
bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
422
0
  if (reg_info) {
423
    // Saved registers are ebx, ebp, esi, edi, esp, eip
424
0
    const char *name = reg_info->name;
425
0
    if (name[0] == 'e') {
426
0
      switch (name[1]) {
427
0
      case 'b':
428
0
        if (name[2] == 'x' || name[2] == 'p')
429
0
          return name[3] == '\0';
430
0
        break;
431
0
      case 'd':
432
0
        if (name[2] == 'i')
433
0
          return name[3] == '\0';
434
0
        break;
435
0
      case 'i':
436
0
        if (name[2] == 'p')
437
0
          return name[3] == '\0';
438
0
        break;
439
0
      case 's':
440
0
        if (name[2] == 'i' || name[2] == 'p')
441
0
          return name[3] == '\0';
442
0
        break;
443
0
      }
444
0
    }
445
0
    if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
446
0
      return true;
447
0
    if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
448
0
      return true;
449
0
    if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
450
0
      return true;
451
0
  }
452
0
  return false;
453
0
}
454
455
3.44k
void ABIMacOSX_i386::Initialize() {
456
3.44k
  PluginManager::RegisterPlugin(
457
3.44k
      GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);
458
3.44k
}
459
460
3.43k
void ABIMacOSX_i386::Terminate() {
461
3.43k
  PluginManager::UnregisterPlugin(CreateInstance);
462
3.43k
}