blob: 9bb8eeab1d2e6311e3468d2e424a7504b285bcb2 [file] [log] [blame]
Kate Stoneb9c1b512016-09-06 20:57:50 +00001//===-- CF.cpp ----------------------------------------------------*- C++
2//-*-===//
Enrico Granata92373532013-03-19 22:58:48 +00003//
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
Enrico Granata170c3952015-09-14 22:18:32 +000011#include "CF.h"
Enrico Granata92373532013-03-19 22:58:48 +000012
Enrico Granata92373532013-03-19 22:58:48 +000013#include "lldb/Core/ValueObject.h"
14#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000015#include "lldb/DataFormatters/FormattersHelpers.h"
Enrico Granata92373532013-03-19 22:58:48 +000016#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata675f49b2015-10-07 18:36:53 +000017#include "lldb/Target/Language.h"
Enrico Granata92373532013-03-19 22:58:48 +000018#include "lldb/Target/ObjCLanguageRuntime.h"
Jim Inghama309efe2015-10-28 22:23:17 +000019#include "lldb/Target/StackFrame.h"
Enrico Granata92373532013-03-19 22:58:48 +000020#include "lldb/Target/Target.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000021#include "lldb/Utility/DataBufferHeap.h"
Zachary Turner01c32432017-02-14 19:06:07 +000022#include "lldb/Utility/Endian.h"
Zachary Turner97206d52017-05-12 04:51:55 +000023#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000024#include "lldb/Utility/Stream.h"
Enrico Granata92373532013-03-19 22:58:48 +000025
26using namespace lldb;
27using namespace lldb_private;
28using namespace lldb_private::formatters;
29
Kate Stoneb9c1b512016-09-06 20:57:50 +000030bool 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;
Enrico Granata92373532013-03-19 22:58:48 +000044}
45
Kate Stoneb9c1b512016-09-06 20:57:50 +000046bool lldb_private::formatters::CFBagSummaryProvider(
47 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
48 static ConstString g_TypeHint("CFBag");
Enrico Granata92373532013-03-19 22:58:48 +000049
Kate Stoneb9c1b512016-09-06 20:57:50 +000050 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;
Enrico Granata92373532013-03-19 22:58:48 +000086 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000087 }
88
89 if (is_type_ok) {
90 lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
Zachary Turner97206d52017-05-12 04:51:55 +000091 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +000092 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
Enrico Granata92373532013-03-19 22:58:48 +000093 if (error.Fail())
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 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();
Enrico Granata92373532013-03-19 22:58:48 +0000104 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105 }
106
107 stream.Printf("%s\"%u value%s\"%s", prefix.c_str(), count,
108 (count == 1 ? "" : "s"), suffix.c_str());
109 return true;
Enrico Granata92373532013-03-19 22:58:48 +0000110}
111
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112bool 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;
Enrico Granataf96fd0d2016-04-08 22:49:31 +0000117
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118 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;
Enrico Granata92373532013-03-19 22:58:48 +0000149 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 }
151
152 if (is_type_ok == false)
153 return false;
154
Zachary Turner97206d52017-05-12 04:51:55 +0000155 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156 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;
Enrico Granata92373532013-03-19 22:58:48 +0000203 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000204 if (count) {
205 stream.Printf("%c", bit6 ? '1' : '0');
206 count -= 1;
Enrico Granata675f49b2015-10-07 18:36:53 +0000207 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000208 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
234bool 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;
Zachary Turner97206d52017-05-12 04:51:55 +0000284 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285 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;
Enrico Granata92373532013-03-19 22:58:48 +0000303}