blob: 7db55e15b5c17dfe658a841c62b350b7fba9e092 [file] [log] [blame]
Kate Stoneb9c1b512016-09-06 20:57:50 +00001//===-- CF.cpp ----------------------------------------------------*- C++
2//-*-===//
Enrico Granata92373532013-03-19 22:58:48 +00003//
Chandler Carruth2946cd72019-01-19 08:50:56 +00004// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Enrico Granata92373532013-03-19 22:58:48 +00007//
8//===----------------------------------------------------------------------===//
9
Enrico Granata170c3952015-09-14 22:18:32 +000010#include "CF.h"
Enrico Granata92373532013-03-19 22:58:48 +000011
Enrico Granata92373532013-03-19 22:58:48 +000012#include "lldb/Core/ValueObject.h"
13#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000014#include "lldb/DataFormatters/FormattersHelpers.h"
Enrico Granata92373532013-03-19 22:58:48 +000015#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata675f49b2015-10-07 18:36:53 +000016#include "lldb/Target/Language.h"
Enrico Granata92373532013-03-19 22:58:48 +000017#include "lldb/Target/ObjCLanguageRuntime.h"
Jim Inghama309efe2015-10-28 22:23:17 +000018#include "lldb/Target/StackFrame.h"
Enrico Granata92373532013-03-19 22:58:48 +000019#include "lldb/Target/Target.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000020#include "lldb/Utility/DataBufferHeap.h"
Zachary Turner01c32432017-02-14 19:06:07 +000021#include "lldb/Utility/Endian.h"
Zachary Turner97206d52017-05-12 04:51:55 +000022#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000023#include "lldb/Utility/Stream.h"
Enrico Granata92373532013-03-19 22:58:48 +000024
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::formatters;
28
Kate Stoneb9c1b512016-09-06 20:57:50 +000029bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(
30 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
31 time_t epoch = GetOSXEpoch();
32 epoch = epoch + (time_t)valobj.GetValueAsUnsigned(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;
Enrico Granata92373532013-03-19 22:58:48 +000043}
44
Kate Stoneb9c1b512016-09-06 20:57:50 +000045bool lldb_private::formatters::CFBagSummaryProvider(
46 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
47 static ConstString g_TypeHint("CFBag");
Enrico Granata92373532013-03-19 22:58:48 +000048
Kate Stoneb9c1b512016-09-06 20:57:50 +000049 ProcessSP process_sp = valobj.GetProcessSP();
50 if (!process_sp)
51 return false;
52
53 ObjCLanguageRuntime *runtime =
54 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
55 lldb::eLanguageTypeObjC);
56
57 if (!runtime)
58 return false;
59
60 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
61 runtime->GetClassDescriptor(valobj));
62
63 if (!descriptor.get() || !descriptor->IsValid())
64 return false;
65
66 uint32_t ptr_size = process_sp->GetAddressByteSize();
67
68 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
69
70 if (!valobj_addr)
71 return false;
72
73 uint32_t count = 0;
74
75 bool is_type_ok = false; // check to see if this is a CFBag we know about
76 if (descriptor->IsCFType()) {
77 ConstString type_name(valobj.GetTypeName());
78
79 static ConstString g___CFBag("__CFBag");
80 static ConstString g_conststruct__CFBag("const struct __CFBag");
81
82 if (type_name == g___CFBag || type_name == g_conststruct__CFBag) {
83 if (valobj.IsPointerType())
84 is_type_ok = true;
Enrico Granata92373532013-03-19 22:58:48 +000085 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000086 }
87
88 if (is_type_ok) {
89 lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
Zachary Turner97206d52017-05-12 04:51:55 +000090 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +000091 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
Enrico Granata92373532013-03-19 22:58:48 +000092 if (error.Fail())
Kate Stoneb9c1b512016-09-06 20:57:50 +000093 return false;
94 } else
95 return false;
96
97 std::string prefix, suffix;
98 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
99 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
100 suffix)) {
101 prefix.clear();
102 suffix.clear();
Enrico Granata92373532013-03-19 22:58:48 +0000103 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 }
105
106 stream.Printf("%s\"%u value%s\"%s", prefix.c_str(), count,
107 (count == 1 ? "" : "s"), suffix.c_str());
108 return true;
Enrico Granata92373532013-03-19 22:58:48 +0000109}
110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111bool lldb_private::formatters::CFBitVectorSummaryProvider(
112 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
113 ProcessSP process_sp = valobj.GetProcessSP();
114 if (!process_sp)
115 return false;
Enrico Granataf96fd0d2016-04-08 22:49:31 +0000116
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117 ObjCLanguageRuntime *runtime =
118 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
119 lldb::eLanguageTypeObjC);
120
121 if (!runtime)
122 return false;
123
124 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
125 runtime->GetClassDescriptor(valobj));
126
127 if (!descriptor.get() || !descriptor->IsValid())
128 return false;
129
130 uint32_t ptr_size = process_sp->GetAddressByteSize();
131
132 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
133
134 if (!valobj_addr)
135 return false;
136
137 uint32_t count = 0;
138
139 bool is_type_ok = false; // check to see if this is a CFBag we know about
140 if (descriptor->IsCFType()) {
141 ConstString type_name(valobj.GetTypeName());
Raphael Isemann05cfdb02019-04-26 07:21:36 +0000142 if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||
143 type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000144 if (valobj.IsPointerType())
145 is_type_ok = true;
Enrico Granata92373532013-03-19 22:58:48 +0000146 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 }
148
Jonas Devliegherea6682a42018-12-15 00:15:33 +0000149 if (!is_type_ok)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 return false;
151
Zachary Turner97206d52017-05-12 04:51:55 +0000152 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
154 ptr_size, 0, error);
155 if (error.Fail())
156 return false;
157 uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
158 addr_t data_ptr = process_sp->ReadPointerFromMemory(
159 valobj_addr + 2 * ptr_size + 2 * ptr_size, error);
160 if (error.Fail())
161 return false;
162 // make sure we do not try to read huge amounts of data
163 if (num_bytes > 1024)
164 num_bytes = 1024;
165 DataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));
166 num_bytes =
167 process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
168 if (error.Fail() || num_bytes == 0)
169 return false;
170 uint8_t *bytes = buffer_sp->GetBytes();
171 for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {
172 uint8_t byte = bytes[byte_idx];
173 bool bit0 = (byte & 1) == 1;
174 bool bit1 = (byte & 2) == 2;
175 bool bit2 = (byte & 4) == 4;
176 bool bit3 = (byte & 8) == 8;
177 bool bit4 = (byte & 16) == 16;
178 bool bit5 = (byte & 32) == 32;
179 bool bit6 = (byte & 64) == 64;
180 bool bit7 = (byte & 128) == 128;
181 stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),
182 (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),
183 (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));
184 count -= 8;
185 }
186 {
187 // print the last byte ensuring we do not print spurious bits
188 uint8_t byte = bytes[num_bytes - 1];
189 bool bit0 = (byte & 1) == 1;
190 bool bit1 = (byte & 2) == 2;
191 bool bit2 = (byte & 4) == 4;
192 bool bit3 = (byte & 8) == 8;
193 bool bit4 = (byte & 16) == 16;
194 bool bit5 = (byte & 32) == 32;
195 bool bit6 = (byte & 64) == 64;
196 bool bit7 = (byte & 128) == 128;
197 if (count) {
198 stream.Printf("%c", bit7 ? '1' : '0');
199 count -= 1;
Enrico Granata92373532013-03-19 22:58:48 +0000200 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 if (count) {
202 stream.Printf("%c", bit6 ? '1' : '0');
203 count -= 1;
Enrico Granata675f49b2015-10-07 18:36:53 +0000204 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000205 if (count) {
206 stream.Printf("%c", bit5 ? '1' : '0');
207 count -= 1;
208 }
209 if (count) {
210 stream.Printf("%c", bit4 ? '1' : '0');
211 count -= 1;
212 }
213 if (count) {
214 stream.Printf("%c", bit3 ? '1' : '0');
215 count -= 1;
216 }
217 if (count) {
218 stream.Printf("%c", bit2 ? '1' : '0');
219 count -= 1;
220 }
221 if (count) {
222 stream.Printf("%c", bit1 ? '1' : '0');
223 count -= 1;
224 }
225 if (count)
226 stream.Printf("%c", bit0 ? '1' : '0');
227 }
228 return true;
229}
230
231bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
232 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
233 static ConstString g_TypeHint("CFBinaryHeap");
234
235 ProcessSP process_sp = valobj.GetProcessSP();
236 if (!process_sp)
237 return false;
238
239 ObjCLanguageRuntime *runtime =
240 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
241 lldb::eLanguageTypeObjC);
242
243 if (!runtime)
244 return false;
245
246 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
247 runtime->GetClassDescriptor(valobj));
248
249 if (!descriptor.get() || !descriptor->IsValid())
250 return false;
251
252 uint32_t ptr_size = process_sp->GetAddressByteSize();
253
254 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
255
256 if (!valobj_addr)
257 return false;
258
259 uint32_t count = 0;
260
261 bool is_type_ok =
262 false; // check to see if this is a CFBinaryHeap we know about
263 if (descriptor->IsCFType()) {
264 ConstString type_name(valobj.GetTypeName());
265
266 static ConstString g___CFBinaryHeap("__CFBinaryHeap");
267 static ConstString g_conststruct__CFBinaryHeap(
268 "const struct __CFBinaryHeap");
269 static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");
270
271 if (type_name == g___CFBinaryHeap ||
272 type_name == g_conststruct__CFBinaryHeap ||
273 type_name == g_CFBinaryHeapRef) {
274 if (valobj.IsPointerType())
275 is_type_ok = true;
276 }
277 }
278
279 if (is_type_ok) {
280 lldb::addr_t offset = 2 * ptr_size + valobj_addr;
Zachary Turner97206d52017-05-12 04:51:55 +0000281 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000282 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
283 if (error.Fail())
284 return false;
285 } else
286 return false;
287
288 std::string prefix, suffix;
289 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
290 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
291 suffix)) {
292 prefix.clear();
293 suffix.clear();
294 }
295 }
296
297 stream.Printf("%s\"%u item%s\"%s", prefix.c_str(), count,
298 (count == 1 ? "" : "s"), suffix.c_str());
299 return true;
Enrico Granata92373532013-03-19 22:58:48 +0000300}