Coverage Report

Created: 2022-01-15 10:30

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/ObjC/CF.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- CF.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 "CF.h"
10
11
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12
#include "lldb/Core/ValueObject.h"
13
#include "lldb/Core/ValueObjectConstResult.h"
14
#include "lldb/DataFormatters/FormattersHelpers.h"
15
#include "lldb/Target/Language.h"
16
#include "lldb/Target/StackFrame.h"
17
#include "lldb/Target/Target.h"
18
#include "lldb/Utility/DataBufferHeap.h"
19
#include "lldb/Utility/Endian.h"
20
#include "lldb/Utility/Status.h"
21
#include "lldb/Utility/Stream.h"
22
23
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
24
25
using namespace lldb;
26
using namespace lldb_private;
27
using namespace lldb_private::formatters;
28
29
bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(
30
45
    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
31
45
  time_t epoch = GetOSXEpoch();
32
45
  epoch = epoch + (time_t)valobj.GetValueAsSigned(0);
33
45
  tm *tm_date = localtime(&epoch);
34
45
  if (!tm_date)
35
0
    return false;
36
45
  std::string buffer(1024, 0);
37
45
  if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
38
0
    return false;
39
45
  stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
40
45
                tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
41
45
                tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
42
45
  return true;
43
45
}
44
45
bool lldb_private::formatters::CFBagSummaryProvider(
46
0
    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
47
0
  static ConstString g_TypeHint("CFBag");
48
49
0
  ProcessSP process_sp = valobj.GetProcessSP();
50
0
  if (!process_sp)
51
0
    return false;
52
53
0
  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
54
55
0
  if (!runtime)
56
0
    return false;
57
58
0
  ObjCLanguageRuntime::ClassDescriptorSP descriptor(
59
0
      runtime->GetClassDescriptor(valobj));
60
61
0
  if (!descriptor.get() || !descriptor->IsValid())
62
0
    return false;
63
64
0
  uint32_t ptr_size = process_sp->GetAddressByteSize();
65
66
0
  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
67
68
0
  if (!valobj_addr)
69
0
    return false;
70
71
0
  uint32_t count = 0;
72
73
0
  bool is_type_ok = false; // check to see if this is a CFBag we know about
74
0
  if (descriptor->IsCFType()) {
75
0
    ConstString type_name(valobj.GetTypeName());
76
77
0
    static ConstString g___CFBag("__CFBag");
78
0
    static ConstString g_conststruct__CFBag("const struct __CFBag");
79
80
0
    if (type_name == g___CFBag || type_name == g_conststruct__CFBag) {
81
0
      if (valobj.IsPointerType())
82
0
        is_type_ok = true;
83
0
    }
84
0
  }
85
86
0
  if (is_type_ok) {
87
0
    lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
88
0
    Status error;
89
0
    count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
90
0
    if (error.Fail())
91
0
      return false;
92
0
  } else
93
0
    return false;
94
95
0
  std::string prefix, suffix;
96
0
  if (Language *language = Language::FindPlugin(options.GetLanguage())) {
97
0
    if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
98
0
                                            suffix)) {
99
0
      prefix.clear();
100
0
      suffix.clear();
101
0
    }
102
0
  }
103
104
0
  stream.Printf("%s\"%u value%s\"%s", prefix.c_str(), count,
105
0
                (count == 1 ? "" : "s"), suffix.c_str());
106
0
  return true;
107
0
}
108
109
bool lldb_private::formatters::CFBitVectorSummaryProvider(
110
9
    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
111
9
  ProcessSP process_sp = valobj.GetProcessSP();
112
9
  if (!process_sp)
113
0
    return false;
114
115
9
  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
116
117
9
  if (!runtime)
118
0
    return false;
119
120
9
  ObjCLanguageRuntime::ClassDescriptorSP descriptor(
121
9
      runtime->GetClassDescriptor(valobj));
122
123
9
  if (!descriptor.get() || !descriptor->IsValid())
124
0
    return false;
125
126
9
  uint32_t ptr_size = process_sp->GetAddressByteSize();
127
128
9
  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
129
130
9
  if (!valobj_addr)
131
0
    return false;
132
133
9
  uint32_t count = 0;
134
135
9
  bool is_type_ok = false; // check to see if this is a CFBag we know about
136
9
  if (descriptor->IsCFType()) {
137
9
    ConstString type_name(valobj.GetTypeName());
138
9
    if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||
139
9
        type_name == "CFMutableBitVectorRef" || 
type_name == "CFBitVectorRef"0
) {
140
9
      if (valobj.IsPointerType())
141
9
        is_type_ok = true;
142
9
    }
143
9
  }
144
145
9
  if (!is_type_ok)
146
0
    return false;
147
148
9
  Status error;
149
9
  count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
150
9
                                                    ptr_size, 0, error);
151
9
  if (error.Fail())
152
0
    return false;
153
9
  uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 
00
);
154
9
  addr_t data_ptr = process_sp->ReadPointerFromMemory(
155
9
      valobj_addr + 2 * ptr_size + 2 * ptr_size, error);
156
9
  if (error.Fail())
157
0
    return false;
158
  // make sure we do not try to read huge amounts of data
159
9
  if (num_bytes > 1024)
160
0
    num_bytes = 1024;
161
9
  DataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));
162
9
  num_bytes =
163
9
      process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
164
9
  if (error.Fail() || num_bytes == 0)
165
0
    return false;
166
9
  uint8_t *bytes = buffer_sp->GetBytes();
167
63
  for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; 
byte_idx++54
) {
168
54
    uint8_t byte = bytes[byte_idx];
169
54
    bool bit0 = (byte & 1) == 1;
170
54
    bool bit1 = (byte & 2) == 2;
171
54
    bool bit2 = (byte & 4) == 4;
172
54
    bool bit3 = (byte & 8) == 8;
173
54
    bool bit4 = (byte & 16) == 16;
174
54
    bool bit5 = (byte & 32) == 32;
175
54
    bool bit6 = (byte & 64) == 64;
176
54
    bool bit7 = (byte & 128) == 128;
177
54
    stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? 
'1'45
:
'0'9
), (bit6 ?
'1'27
:
'0'27
),
178
54
                  (bit5 ? 
'1'27
:
'0'27
), (bit4 ?
'1'36
:
'0'18
), (bit3 ?
'1'18
:
'0'36
),
179
54
                  (bit2 ? 
'1'27
:
'0'27
), (bit1 ?
'1'27
:
'0'27
), (bit0 ?
'1'27
:
'0'27
));
180
54
    count -= 8;
181
54
  }
182
9
  {
183
    // print the last byte ensuring we do not print spurious bits
184
9
    uint8_t byte = bytes[num_bytes - 1];
185
9
    bool bit0 = (byte & 1) == 1;
186
9
    bool bit1 = (byte & 2) == 2;
187
9
    bool bit2 = (byte & 4) == 4;
188
9
    bool bit3 = (byte & 8) == 8;
189
9
    bool bit4 = (byte & 16) == 16;
190
9
    bool bit5 = (byte & 32) == 32;
191
9
    bool bit6 = (byte & 64) == 64;
192
9
    bool bit7 = (byte & 128) == 128;
193
9
    if (count) {
194
9
      stream.Printf("%c", bit7 ? 
'1'0
: '0');
195
9
      count -= 1;
196
9
    }
197
9
    if (count) {
198
9
      stream.Printf("%c", bit6 ? 
'1'0
: '0');
199
9
      count -= 1;
200
9
    }
201
9
    if (count) {
202
0
      stream.Printf("%c", bit5 ? '1' : '0');
203
0
      count -= 1;
204
0
    }
205
9
    if (count) {
206
0
      stream.Printf("%c", bit4 ? '1' : '0');
207
0
      count -= 1;
208
0
    }
209
9
    if (count) {
210
0
      stream.Printf("%c", bit3 ? '1' : '0');
211
0
      count -= 1;
212
0
    }
213
9
    if (count) {
214
0
      stream.Printf("%c", bit2 ? '1' : '0');
215
0
      count -= 1;
216
0
    }
217
9
    if (count) {
218
0
      stream.Printf("%c", bit1 ? '1' : '0');
219
0
      count -= 1;
220
0
    }
221
9
    if (count)
222
0
      stream.Printf("%c", bit0 ? '1' : '0');
223
9
  }
224
9
  return true;
225
9
}
226
227
bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
228
15
    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
229
15
  static ConstString g_TypeHint("CFBinaryHeap");
230
231
15
  ProcessSP process_sp = valobj.GetProcessSP();
232
15
  if (!process_sp)
233
0
    return false;
234
235
15
  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
236
237
15
  if (!runtime)
238
0
    return false;
239
240
15
  ObjCLanguageRuntime::ClassDescriptorSP descriptor(
241
15
      runtime->GetClassDescriptor(valobj));
242
243
15
  if (!descriptor.get() || !descriptor->IsValid())
244
0
    return false;
245
246
15
  uint32_t ptr_size = process_sp->GetAddressByteSize();
247
248
15
  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
249
250
15
  if (!valobj_addr)
251
0
    return false;
252
253
15
  uint32_t count = 0;
254
255
15
  bool is_type_ok =
256
15
      false; // check to see if this is a CFBinaryHeap we know about
257
15
  if (descriptor->IsCFType()) {
258
15
    ConstString type_name(valobj.GetTypeName());
259
260
15
    static ConstString g___CFBinaryHeap("__CFBinaryHeap");
261
15
    static ConstString g_conststruct__CFBinaryHeap(
262
15
        "const struct __CFBinaryHeap");
263
15
    static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");
264
265
15
    if (type_name == g___CFBinaryHeap ||
266
15
        type_name == g_conststruct__CFBinaryHeap ||
267
15
        type_name == g_CFBinaryHeapRef) {
268
15
      if (valobj.IsPointerType())
269
15
        is_type_ok = true;
270
15
    }
271
15
  }
272
273
15
  if (is_type_ok) {
274
15
    lldb::addr_t offset = 2 * ptr_size + valobj_addr;
275
15
    Status error;
276
15
    count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
277
15
    if (error.Fail())
278
0
      return false;
279
15
  } else
280
0
    return false;
281
282
15
  std::string prefix, suffix;
283
15
  if (Language *language = Language::FindPlugin(options.GetLanguage())) {
284
15
    if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
285
15
                                            suffix)) {
286
0
      prefix.clear();
287
0
      suffix.clear();
288
0
    }
289
15
  }
290
291
15
  stream.Printf("%s\"%u item%s\"%s", prefix.c_str(), count,
292
15
                (count == 1 ? 
""6
:
"s"9
), suffix.c_str());
293
15
  return true;
294
15
}