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