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