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