1 //===-- CF.cpp ------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
23 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
26 using namespace lldb_private
;
27 using namespace lldb_private::formatters
;
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
);
36 std::string
buffer(1024, 0);
37 if (strftime(&buffer
[0], 1023, "%Z", tm_date
) == 0)
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());
45 bool lldb_private::formatters::CFBagSummaryProvider(
46 ValueObject
&valobj
, Stream
&stream
, const TypeSummaryOptions
&options
) {
47 static constexpr llvm::StringLiteral
g_TypeHint("CFBag");
49 ProcessSP process_sp
= valobj
.GetProcessSP();
53 ObjCLanguageRuntime
*runtime
= ObjCLanguageRuntime::Get(*process_sp
);
58 ObjCLanguageRuntime::ClassDescriptorSP
descriptor(
59 runtime
->GetClassDescriptor(valobj
));
61 if (!descriptor
.get() || !descriptor
->IsValid())
64 uint32_t ptr_size
= process_sp
->GetAddressByteSize();
66 lldb::addr_t valobj_addr
= valobj
.GetValueAsUnsigned(0);
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());
77 static ConstString
g_CFBag("__CFBag");
78 static ConstString
g_conststruct__CFBag("const struct __CFBag");
80 if (type_name
== g_CFBag
|| type_name
== g_conststruct__CFBag
) {
81 if (valobj
.IsPointerType())
87 lldb::addr_t offset
= 2 * ptr_size
+ 4 + valobj_addr
;
89 count
= process_sp
->ReadUnsignedIntegerFromMemory(offset
, 4, 0, error
);
95 llvm::StringRef prefix
, suffix
;
96 if (Language
*language
= Language::FindPlugin(options
.GetLanguage()))
97 std::tie(prefix
, suffix
) = language
->GetFormatterPrefixSuffix(g_TypeHint
);
100 stream
.Printf("\"%u value%s\"", count
, (count
== 1 ? "" : "s"));
105 bool lldb_private::formatters::CFBitVectorSummaryProvider(
106 ValueObject
&valobj
, Stream
&stream
, const TypeSummaryOptions
&options
) {
107 ProcessSP process_sp
= valobj
.GetProcessSP();
111 ObjCLanguageRuntime
*runtime
= ObjCLanguageRuntime::Get(*process_sp
);
116 ObjCLanguageRuntime::ClassDescriptorSP
descriptor(
117 runtime
->GetClassDescriptor(valobj
));
119 if (!descriptor
.get() || !descriptor
->IsValid())
122 uint32_t ptr_size
= process_sp
->GetAddressByteSize();
124 lldb::addr_t valobj_addr
= valobj
.GetValueAsUnsigned(0);
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())
145 count
= process_sp
->ReadUnsignedIntegerFromMemory(valobj_addr
+ 2 * ptr_size
,
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
);
154 // make sure we do not try to read huge amounts of data
155 if (num_bytes
> 1024)
157 WritableDataBufferSP
buffer_sp(new DataBufferHeap(num_bytes
, 0));
159 process_sp
->ReadMemory(data_ptr
, buffer_sp
->GetBytes(), num_bytes
, error
);
160 if (error
.Fail() || num_bytes
== 0)
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'));
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;
190 stream
.Printf("%c", bit7
? '1' : '0');
194 stream
.Printf("%c", bit6
? '1' : '0');
198 stream
.Printf("%c", bit5
? '1' : '0');
202 stream
.Printf("%c", bit4
? '1' : '0');
206 stream
.Printf("%c", bit3
? '1' : '0');
210 stream
.Printf("%c", bit2
? '1' : '0');
214 stream
.Printf("%c", bit1
? '1' : '0');
218 stream
.Printf("%c", bit0
? '1' : '0');
223 bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
224 ValueObject
&valobj
, Stream
&stream
, const TypeSummaryOptions
&options
) {
225 static constexpr llvm::StringLiteral
g_TypeHint("CFBinaryHeap");
227 ProcessSP process_sp
= valobj
.GetProcessSP();
231 ObjCLanguageRuntime
*runtime
= ObjCLanguageRuntime::Get(*process_sp
);
236 ObjCLanguageRuntime::ClassDescriptorSP
descriptor(
237 runtime
->GetClassDescriptor(valobj
));
239 if (!descriptor
.get() || !descriptor
->IsValid())
242 uint32_t ptr_size
= process_sp
->GetAddressByteSize();
244 lldb::addr_t valobj_addr
= valobj
.GetValueAsUnsigned(0);
252 false; // check to see if this is a CFBinaryHeap we know about
253 if (descriptor
->IsCFType()) {
254 ConstString
type_name(valobj
.GetTypeName());
256 static ConstString
g_CFBinaryHeap("__CFBinaryHeap");
257 static ConstString
g_conststruct__CFBinaryHeap(
258 "const struct __CFBinaryHeap");
259 static ConstString
g_CFBinaryHeapRef("CFBinaryHeapRef");
261 if (type_name
== g_CFBinaryHeap
||
262 type_name
== g_conststruct__CFBinaryHeap
||
263 type_name
== g_CFBinaryHeapRef
) {
264 if (valobj
.IsPointerType())
270 lldb::addr_t offset
= 2 * ptr_size
+ valobj_addr
;
272 count
= process_sp
->ReadUnsignedIntegerFromMemory(offset
, 4, 0, error
);
278 llvm::StringRef prefix
, suffix
;
279 if (Language
*language
= Language::FindPlugin(options
.GetLanguage()))
280 std::tie(prefix
, suffix
) = language
->GetFormatterPrefixSuffix(g_TypeHint
);
283 stream
.Printf("\"%u item%s\"", count
, (count
== 1 ? "" : "s"));