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