blob: a381902512888bfab391e9ca26410cad35a6e564 [file] [log] [blame]
Enrico Granatacaaf0102012-09-04 18:48:21 +00001//===-- CXXFormatterFunctions.cpp---------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Daniel Malead891f9b2012-12-05 00:20:57 +000010#include "lldb/lldb-python.h"
11
Enrico Granataf509c5e2013-01-28 23:47:25 +000012#include "lldb/DataFormatters/CXXFormatterFunctions.h"
Enrico Granatacaaf0102012-09-04 18:48:21 +000013
14// needed to get ConvertUTF16/32ToUTF8
15#define CLANG_NEEDS_THESE_ONE_DAY
16#include "clang/Basic/ConvertUTF.h"
17
Enrico Granataf91e78f2012-09-13 18:27:09 +000018#include "lldb/Core/DataBufferHeap.h"
19#include "lldb/Core/Error.h"
Enrico Granatacaaf0102012-09-04 18:48:21 +000020#include "lldb/Core/Stream.h"
21#include "lldb/Core/ValueObject.h"
Enrico Granataf91e78f2012-09-13 18:27:09 +000022#include "lldb/Core/ValueObjectConstResult.h"
23#include "lldb/Host/Endian.h"
Enrico Granatadb054912012-10-29 21:18:03 +000024#include "lldb/Symbol/ClangASTContext.h"
Enrico Granatacaaf0102012-09-04 18:48:21 +000025#include "lldb/Target/ObjCLanguageRuntime.h"
26#include "lldb/Target/Target.h"
27
28using namespace lldb;
29using namespace lldb_private;
30using namespace lldb_private::formatters;
31
32bool
Enrico Granataf91e78f2012-09-13 18:27:09 +000033lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
34 const char* target_type,
35 const char* selector,
36 uint64_t &value)
Enrico Granatacaaf0102012-09-04 18:48:21 +000037{
38 if (!target_type || !*target_type)
39 return false;
40 if (!selector || !*selector)
41 return false;
Enrico Granatacaaf0102012-09-04 18:48:21 +000042 StreamString expr;
Daniel Maleab9db9d52012-12-07 22:21:08 +000043 expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
Enrico Granatacaaf0102012-09-04 18:48:21 +000044 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
45 lldb::ValueObjectSP result_sp;
46 Target* target = exe_ctx.GetTargetPtr();
47 StackFrame* stack_frame = exe_ctx.GetFramePtr();
48 if (!target || !stack_frame)
49 return false;
Enrico Granatad27026e2012-09-05 20:41:26 +000050
Jim Ingham47beabb2012-10-16 21:41:58 +000051 EvaluateExpressionOptions options;
Enrico Granatad27026e2012-09-05 20:41:26 +000052 options.SetCoerceToId(false)
53 .SetUnwindOnError(true)
Sean Callanan99611fe2012-12-04 20:56:04 +000054 .SetKeepInMemory(true);
Enrico Granatad27026e2012-09-05 20:41:26 +000055
Enrico Granatacaaf0102012-09-04 18:48:21 +000056 target->EvaluateExpression(expr.GetData(),
57 stack_frame,
Enrico Granatad27026e2012-09-05 20:41:26 +000058 result_sp,
59 options);
Enrico Granatacaaf0102012-09-04 18:48:21 +000060 if (!result_sp)
61 return false;
62 value = result_sp->GetValueAsUnsigned(0);
63 return true;
64}
65
Enrico Granataf91e78f2012-09-13 18:27:09 +000066lldb::ValueObjectSP
67lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
68 const char* return_type,
69 const char* selector,
70 uint64_t index)
71{
72 lldb::ValueObjectSP valobj_sp;
73 if (!return_type || !*return_type)
74 return valobj_sp;
75 if (!selector || !*selector)
76 return valobj_sp;
77 StreamString expr_path_stream;
78 valobj.GetExpressionPath(expr_path_stream, false);
79 StreamString expr;
Daniel Malea5f35a4b2012-11-29 21:49:15 +000080 expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index);
Enrico Granataf91e78f2012-09-13 18:27:09 +000081 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
82 lldb::ValueObjectSP result_sp;
83 Target* target = exe_ctx.GetTargetPtr();
84 StackFrame* stack_frame = exe_ctx.GetFramePtr();
85 if (!target || !stack_frame)
86 return valobj_sp;
87
Jim Ingham47beabb2012-10-16 21:41:58 +000088 EvaluateExpressionOptions options;
Enrico Granataf91e78f2012-09-13 18:27:09 +000089 options.SetCoerceToId(false)
90 .SetUnwindOnError(true)
91 .SetKeepInMemory(true)
92 .SetUseDynamic(lldb::eDynamicCanRunTarget);
93
94 target->EvaluateExpression(expr.GetData(),
95 stack_frame,
96 valobj_sp,
97 options);
98 return valobj_sp;
99}
100
101lldb::ValueObjectSP
102lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
103 const char* return_type,
104 const char* selector,
105 const char* key)
106{
107 lldb::ValueObjectSP valobj_sp;
108 if (!return_type || !*return_type)
109 return valobj_sp;
110 if (!selector || !*selector)
111 return valobj_sp;
112 if (!key || !*key)
113 return valobj_sp;
114 StreamString expr_path_stream;
115 valobj.GetExpressionPath(expr_path_stream, false);
116 StreamString expr;
117 expr.Printf("(%s)[%s %s:%s]",return_type,expr_path_stream.GetData(),selector,key);
118 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
119 lldb::ValueObjectSP result_sp;
120 Target* target = exe_ctx.GetTargetPtr();
121 StackFrame* stack_frame = exe_ctx.GetFramePtr();
122 if (!target || !stack_frame)
123 return valobj_sp;
124
Jim Ingham47beabb2012-10-16 21:41:58 +0000125 EvaluateExpressionOptions options;
Enrico Granataf91e78f2012-09-13 18:27:09 +0000126 options.SetCoerceToId(false)
127 .SetUnwindOnError(true)
128 .SetKeepInMemory(true)
129 .SetUseDynamic(lldb::eDynamicCanRunTarget);
130
131 target->EvaluateExpression(expr.GetData(),
132 stack_frame,
133 valobj_sp,
134 options);
135 return valobj_sp;
136}
137
Enrico Granatacd8cd612013-01-14 23:53:26 +0000138// use this call if you already have an LLDB-side buffer for the data
139template<typename SourceDataType>
Enrico Granataf5545f92013-01-10 22:08:35 +0000140static bool
Enrico Granatacd8cd612013-01-14 23:53:26 +0000141DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
142 const SourceDataType*,
143 UTF8**,
144 UTF8*,
145 ConversionFlags),
146 DataExtractor& data,
147 Stream& stream,
148 char prefix_token = '@',
149 char quote = '"',
150 int sourceSize = 0)
Enrico Granataf5545f92013-01-10 22:08:35 +0000151{
Enrico Granatacd8cd612013-01-14 23:53:26 +0000152 if (prefix_token != 0)
153 stream.Printf("%c",prefix_token);
154 if (quote != 0)
155 stream.Printf("%c",quote);
156 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
Enrico Granataf5545f92013-01-10 22:08:35 +0000157 {
Enrico Granatacd8cd612013-01-14 23:53:26 +0000158 const int bufferSPSize = data.GetByteSize();
159 if (sourceSize == 0)
160 {
161 const int origin_encoding = 8*sizeof(SourceDataType);
162 sourceSize = bufferSPSize/(origin_encoding >> 2);
163 }
164
165 SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
Enrico Granataf5545f92013-01-10 22:08:35 +0000166 SourceDataType *data_end_ptr = data_ptr + sourceSize;
167
168 while (data_ptr < data_end_ptr)
169 {
170 if (!*data_ptr)
171 {
172 data_end_ptr = data_ptr;
173 break;
174 }
175 data_ptr++;
176 }
177
178 *data_ptr = 0;
Enrico Granatacd8cd612013-01-14 23:53:26 +0000179 data_ptr = (SourceDataType*)data.GetDataStart();
Enrico Granataf5545f92013-01-10 22:08:35 +0000180
Enrico Granata06d58b02013-01-11 02:44:00 +0000181 lldb::DataBufferSP utf8_data_buffer_sp;
182 UTF8* utf8_data_ptr = nullptr;
183 UTF8* utf8_data_end_ptr = nullptr;
Enrico Granatacd8cd612013-01-14 23:53:26 +0000184
Enrico Granataf5545f92013-01-10 22:08:35 +0000185 if (ConvertFunction)
Enrico Granata06d58b02013-01-11 02:44:00 +0000186 {
187 utf8_data_buffer_sp.reset(new DataBufferHeap(bufferSPSize,0));
188 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
189 utf8_data_end_ptr = utf8_data_ptr + bufferSPSize;
Enrico Granataf5545f92013-01-10 22:08:35 +0000190 ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
Enrico Granata06d58b02013-01-11 02:44:00 +0000191 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
192 }
Enrico Granataf5545f92013-01-10 22:08:35 +0000193 else
194 {
195 // just copy the pointers - the cast is necessary to make the compiler happy
196 // but this should only happen if we are reading UTF8 data
197 utf8_data_ptr = (UTF8*)data_ptr;
198 utf8_data_end_ptr = (UTF8*)data_end_ptr;
199 }
200
Enrico Granatab6985792013-01-12 01:00:22 +0000201 // since we tend to accept partial data (and even partially malformed data)
202 // we might end up with no NULL terminator before the end_ptr
203 // hence we need to take a slower route and ensure we stay within boundaries
Enrico Granataf5545f92013-01-10 22:08:35 +0000204 for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
205 {
206 if (!*utf8_data_ptr)
207 break;
208 stream.Printf("%c",*utf8_data_ptr);
209 }
Enrico Granatacd8cd612013-01-14 23:53:26 +0000210 }
211 if (quote != 0)
212 stream.Printf("%c",quote);
213 return true;
214}
215
216template<typename SourceDataType>
217static bool
218ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
219 const SourceDataType*,
220 UTF8**,
221 UTF8*,
222 ConversionFlags),
223 uint64_t location,
224 const ProcessSP& process_sp,
225 Stream& stream,
226 char prefix_token = '@',
227 char quote = '"',
228 int sourceSize = 0)
229{
230 if (location == 0 || location == LLDB_INVALID_ADDRESS)
231 return false;
232 if (!process_sp)
233 return false;
234
235 const int origin_encoding = 8*sizeof(SourceDataType);
236 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
237 return false;
238 // if not UTF8, I need a conversion function to return proper UTF8
239 if (origin_encoding != 8 && !ConvertFunction)
240 return false;
241
242 if (sourceSize == 0)
243 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
244 const int bufferSPSize = sourceSize * (origin_encoding >> 2);
245
246 Error error;
247 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
248
249 if (!buffer_sp->GetBytes())
250 return false;
251
252 size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error);
253 if (error.Fail() || data_read == 0)
254 {
255 stream.Printf("unable to read data");
Enrico Granataf5545f92013-01-10 22:08:35 +0000256 return true;
257 }
Enrico Granatacd8cd612013-01-14 23:53:26 +0000258
259 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
260
261 return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize);
Enrico Granataf5545f92013-01-10 22:08:35 +0000262}
263
264bool
265lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
266{
267 ProcessSP process_sp = valobj.GetProcessSP();
268 if (!process_sp)
269 return false;
270
271 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
272
273 if (!valobj_addr)
274 return false;
275
Enrico Granatacd8cd612013-01-14 23:53:26 +0000276 if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr,
Enrico Granataf5545f92013-01-10 22:08:35 +0000277 process_sp,
278 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000279 'u'))
Enrico Granataf5545f92013-01-10 22:08:35 +0000280 {
281 stream.Printf("Summary Unavailable");
282 return true;
283 }
284
285 return true;
286}
287
288bool
289lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
290{
291 ProcessSP process_sp = valobj.GetProcessSP();
292 if (!process_sp)
293 return false;
294
295 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
296
297 if (!valobj_addr)
298 return false;
299
Enrico Granatacd8cd612013-01-14 23:53:26 +0000300 if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr,
Enrico Granataf5545f92013-01-10 22:08:35 +0000301 process_sp,
302 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000303 'U'))
Enrico Granataf5545f92013-01-10 22:08:35 +0000304 {
305 stream.Printf("Summary Unavailable");
306 return true;
307 }
308
309 return true;
310}
311
312bool
313lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
314{
Enrico Granata06d58b02013-01-11 02:44:00 +0000315 ProcessSP process_sp = valobj.GetProcessSP();
316 if (!process_sp)
317 return false;
318
Enrico Granatab6985792013-01-12 01:00:22 +0000319 lldb::addr_t data_addr = 0;
320
321 if (valobj.IsPointerType())
322 data_addr = valobj.GetValueAsUnsigned(0);
323 else if (valobj.IsArrayType())
324 data_addr = valobj.GetAddressOf();
Enrico Granata06d58b02013-01-11 02:44:00 +0000325
Enrico Granatab6985792013-01-12 01:00:22 +0000326 if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
Enrico Granata06d58b02013-01-11 02:44:00 +0000327 return false;
328
329 clang::ASTContext* ast = valobj.GetClangAST();
330
331 if (!ast)
332 return false;
333
334 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
335
336 switch (wchar_size)
337 {
338 case 8:
339 // utf 8
Enrico Granatacd8cd612013-01-14 23:53:26 +0000340 return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr,
Enrico Granata06d58b02013-01-11 02:44:00 +0000341 process_sp,
342 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000343 'L');
Enrico Granata06d58b02013-01-11 02:44:00 +0000344 case 16:
345 // utf 16
Enrico Granatacd8cd612013-01-14 23:53:26 +0000346 return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr,
Enrico Granata06d58b02013-01-11 02:44:00 +0000347 process_sp,
348 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000349 'L');
Enrico Granata06d58b02013-01-11 02:44:00 +0000350 case 32:
351 // utf 32
Enrico Granatacd8cd612013-01-14 23:53:26 +0000352 return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr,
Enrico Granata06d58b02013-01-11 02:44:00 +0000353 process_sp,
354 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000355 'L');
356 default:
357 stream.Printf("size for wchar_t is not valid");
358 return true;
359 }
360 return true;
361}
362
363bool
364lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
365{
366 DataExtractor data;
367 valobj.GetData(data);
368
369 std::string value;
370 valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
371 if (!value.empty())
372 stream.Printf("%s ", value.c_str());
373
374 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
375}
376
377bool
378lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
379{
380 DataExtractor data;
381 valobj.GetData(data);
382
383 std::string value;
384 valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
385 if (!value.empty())
386 stream.Printf("%s ", value.c_str());
387
388 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
389}
390
391bool
392lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
393{
394 DataExtractor data;
395 valobj.GetData(data);
396
397 clang::ASTContext* ast = valobj.GetClangAST();
398
399 if (!ast)
400 return false;
401
402 std::string value;
403
404 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
405
406 switch (wchar_size)
407 {
408 case 8:
409 // utf 8
410 valobj.GetValueAsCString(lldb::eFormatChar, value);
411 if (!value.empty())
412 stream.Printf("%s ", value.c_str());
413 return DumpUTFBufferToStream<UTF8>(nullptr,
414 data,
415 stream,
416 'L',
417 '\'',
418 1);
419 case 16:
420 // utf 16
421 valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
422 if (!value.empty())
423 stream.Printf("%s ", value.c_str());
424 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
425 data,
426 stream,
427 'L',
428 '\'',
429 1);
430 case 32:
431 // utf 32
432 valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
433 if (!value.empty())
434 stream.Printf("%s ", value.c_str());
435 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
436 data,
437 stream,
438 'L',
439 '\'',
440 1);
Enrico Granata06d58b02013-01-11 02:44:00 +0000441 default:
442 stream.Printf("size for wchar_t is not valid");
443 return true;
444 }
445 return true;
Enrico Granataf5545f92013-01-10 22:08:35 +0000446}
447
Enrico Granatab6985792013-01-12 01:00:22 +0000448// this function extracts information from a libcxx std::basic_string<>
449// irregardless of template arguments. it reports the size (in item count not bytes)
450// and the location in memory where the string data can be found
451static bool
452ExtractLibcxxStringInfo (ValueObject& valobj,
453 ValueObjectSP &location_sp,
454 uint64_t& size)
455{
456 ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
457 if (!D)
458 return false;
459
460 ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
461 if (!size_mode)
462 return false;
463
464 uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0));
465
466 if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline
467 {
468 ValueObjectSP s(D->GetChildAtIndex(1, true));
469 if (!s)
470 return false;
471 size = ((size_mode_value >> 1) % 256);
472 location_sp = s->GetChildAtIndex(1, true);
473 return (location_sp.get() != nullptr);
474 }
475 else
476 {
477 ValueObjectSP l(D->GetChildAtIndex(0, true));
478 if (!l)
479 return false;
480 location_sp = l->GetChildAtIndex(2, true);
481 ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
482 if (!size_vo || !location_sp)
483 return false;
484 size = size_vo->GetValueAsUnsigned(0);
485 return true;
486 }
487}
488
489bool
490lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
491{
492 uint64_t size = 0;
493 ValueObjectSP location_sp((ValueObject*)nullptr);
494 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
495 return false;
496 if (size == 0)
497 {
498 stream.Printf("L\"\"");
499 return true;
500 }
501 if (!location_sp)
502 return false;
503 return WCharStringSummaryProvider(*location_sp.get(), stream);
504}
505
506bool
507lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
508{
509 uint64_t size = 0;
510 ValueObjectSP location_sp((ValueObject*)nullptr);
511 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
512 return false;
513 if (size == 0)
514 {
515 stream.Printf("\"\"");
516 return true;
517 }
518 if (!location_sp)
519 return false;
520 Error error;
521 location_sp->ReadPointedString(stream,
522 error,
523 0, // max length is decided by the settings
524 false); // do not honor array (terminates on first 0 byte even for a char[])
525 return error.Success();
526}
527
Enrico Granatacaaf0102012-09-04 18:48:21 +0000528template<bool name_entries>
529bool
Enrico Granataf91e78f2012-09-13 18:27:09 +0000530lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +0000531{
532 ProcessSP process_sp = valobj.GetProcessSP();
533 if (!process_sp)
534 return false;
535
536 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
537
538 if (!runtime)
539 return false;
540
541 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
542
543 if (!descriptor.get() || !descriptor->IsValid())
544 return false;
545
546 uint32_t ptr_size = process_sp->GetAddressByteSize();
547 bool is_64bit = (ptr_size == 8);
548
549 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
550
551 if (!valobj_addr)
552 return false;
553
554 uint64_t value = 0;
555
556 const char* class_name = descriptor->GetClassName().GetCString();
Enrico Granata7685a562012-09-29 00:47:43 +0000557
558 if (!class_name || !*class_name)
559 return false;
560
Enrico Granatacaaf0102012-09-04 18:48:21 +0000561 if (!strcmp(class_name,"__NSDictionaryI"))
562 {
563 Error error;
564 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
565 if (error.Fail())
566 return false;
567 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
568 }
569 else if (!strcmp(class_name,"__NSDictionaryM"))
570 {
571 Error error;
572 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
573 if (error.Fail())
574 return false;
575 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
576 }
577 else if (!strcmp(class_name,"__NSCFDictionary"))
578 {
579 Error error;
580 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), ptr_size, 0, error);
581 if (error.Fail())
582 return false;
583 if (is_64bit)
584 value &= ~0x0f1f000000000000UL;
Enrico Granata06d58b02013-01-11 02:44:00 +0000585 }
Enrico Granatacaaf0102012-09-04 18:48:21 +0000586 else
587 {
Enrico Granataf91e78f2012-09-13 18:27:09 +0000588 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
Enrico Granatacaaf0102012-09-04 18:48:21 +0000589 return false;
590 }
591
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000592 stream.Printf("%s%" PRIu64 " %s%s",
Enrico Granatacaaf0102012-09-04 18:48:21 +0000593 (name_entries ? "@\"" : ""),
594 value,
595 (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
596 (name_entries ? "\"" : ""));
597 return true;
598}
599
600bool
Enrico Granataf91e78f2012-09-13 18:27:09 +0000601lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +0000602{
603 ProcessSP process_sp = valobj.GetProcessSP();
604 if (!process_sp)
605 return false;
606
607 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
608
609 if (!runtime)
610 return false;
611
612 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
613
614 if (!descriptor.get() || !descriptor->IsValid())
615 return false;
616
617 uint32_t ptr_size = process_sp->GetAddressByteSize();
618
619 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
620
621 if (!valobj_addr)
622 return false;
623
624 uint64_t value = 0;
625
626 const char* class_name = descriptor->GetClassName().GetCString();
Enrico Granata7685a562012-09-29 00:47:43 +0000627
628 if (!class_name || !*class_name)
629 return false;
630
Enrico Granatacaaf0102012-09-04 18:48:21 +0000631 if (!strcmp(class_name,"__NSArrayI"))
632 {
633 Error error;
634 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
635 if (error.Fail())
636 return false;
637 }
638 else if (!strcmp(class_name,"__NSArrayM"))
639 {
640 Error error;
641 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
642 if (error.Fail())
643 return false;
644 }
645 else if (!strcmp(class_name,"__NSCFArray"))
646 {
647 Error error;
648 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
649 if (error.Fail())
650 return false;
651 }
652 else
653 {
Enrico Granataf91e78f2012-09-13 18:27:09 +0000654 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
Enrico Granatacaaf0102012-09-04 18:48:21 +0000655 return false;
656 }
657
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000658 stream.Printf("@\"%" PRIu64 " object%s\"",
Enrico Granatacaaf0102012-09-04 18:48:21 +0000659 value,
660 value == 1 ? "" : "s");
661 return true;
662}
663
664template<bool needs_at>
665bool
Enrico Granataf91e78f2012-09-13 18:27:09 +0000666lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +0000667{
668 ProcessSP process_sp = valobj.GetProcessSP();
669 if (!process_sp)
670 return false;
671
672 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
673
674 if (!runtime)
675 return false;
676
677 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
678
679 if (!descriptor.get() || !descriptor->IsValid())
680 return false;
681
682 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
683 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
684
685 if (!valobj_addr)
686 return false;
687
688 uint64_t value = 0;
689
690 const char* class_name = descriptor->GetClassName().GetCString();
Enrico Granata7685a562012-09-29 00:47:43 +0000691
692 if (!class_name || !*class_name)
693 return false;
694
Enrico Granatacaaf0102012-09-04 18:48:21 +0000695 if (!strcmp(class_name,"NSConcreteData") ||
696 !strcmp(class_name,"NSConcreteMutableData") ||
697 !strcmp(class_name,"__NSCFData"))
698 {
699 uint32_t offset = (is_64bit ? 16 : 8);
700 Error error;
701 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
702 if (error.Fail())
703 return false;
704 }
705 else
706 {
Enrico Granataf91e78f2012-09-13 18:27:09 +0000707 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
Enrico Granatacaaf0102012-09-04 18:48:21 +0000708 return false;
709 }
710
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000711 stream.Printf("%s%" PRIu64 " byte%s%s",
Enrico Granatacaaf0102012-09-04 18:48:21 +0000712 (needs_at ? "@\"" : ""),
713 value,
714 (value > 1 ? "s" : ""),
715 (needs_at ? "\"" : ""));
716
717 return true;
718}
719
720bool
Enrico Granataf91e78f2012-09-13 18:27:09 +0000721lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +0000722{
723 ProcessSP process_sp = valobj.GetProcessSP();
724 if (!process_sp)
725 return false;
726
727 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
728
729 if (!runtime)
730 return false;
731
732 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
733
734 if (!descriptor.get() || !descriptor->IsValid())
735 return false;
736
737 uint32_t ptr_size = process_sp->GetAddressByteSize();
738
739 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
740
741 if (!valobj_addr)
742 return false;
743
744 const char* class_name = descriptor->GetClassName().GetCString();
745
Enrico Granata7685a562012-09-29 00:47:43 +0000746 if (!class_name || !*class_name)
747 return false;
748
Enrico Granatacaaf0102012-09-04 18:48:21 +0000749 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
750 {
751 if (descriptor->IsTagged())
752 {
753 // we have a call to get info and value bits in the tagged descriptor. but we prefer not to cast and replicate them
754 int64_t value = (valobj_addr & ~0x0000000000000000FFL) >> 8;
755 uint64_t i_bits = (valobj_addr & 0xF0) >> 4;
756
757 switch (i_bits)
758 {
759 case 0:
760 stream.Printf("(char)%hhd",(char)value);
761 break;
762 case 4:
763 stream.Printf("(short)%hd",(short)value);
764 break;
765 case 8:
766 stream.Printf("(int)%d",(int)value);
767 break;
768 case 12:
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000769 stream.Printf("(long)%" PRId64,value);
Enrico Granatacaaf0102012-09-04 18:48:21 +0000770 break;
771 default:
Enrico Granata3ca24b42012-12-10 19:23:00 +0000772 stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
Enrico Granatacaaf0102012-09-04 18:48:21 +0000773 break;
774 }
775 return true;
776 }
777 else
778 {
779 Error error;
780 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
781 uint64_t data_location = valobj_addr + 2*ptr_size;
782 uint64_t value = 0;
783 if (error.Fail())
784 return false;
785 switch (data_type)
786 {
787 case 1: // 0B00001
788 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
789 if (error.Fail())
790 return false;
791 stream.Printf("(char)%hhd",(char)value);
792 break;
793 case 2: // 0B0010
794 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
795 if (error.Fail())
796 return false;
797 stream.Printf("(short)%hd",(short)value);
798 break;
799 case 3: // 0B0011
800 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
801 if (error.Fail())
802 return false;
803 stream.Printf("(int)%d",(int)value);
804 break;
805 case 17: // 0B10001
806 data_location += 8;
807 case 4: // 0B0100
808 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
809 if (error.Fail())
810 return false;
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000811 stream.Printf("(long)%" PRId64,value);
Enrico Granatacaaf0102012-09-04 18:48:21 +0000812 break;
813 case 5: // 0B0101
814 {
815 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
816 if (error.Fail())
817 return false;
818 float flt_value = *((float*)&flt_as_int);
819 stream.Printf("(float)%f",flt_value);
820 break;
821 }
822 case 6: // 0B0110
823 {
824 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
825 if (error.Fail())
826 return false;
827 double dbl_value = *((double*)&dbl_as_lng);
828 stream.Printf("(double)%g",dbl_value);
829 break;
830 }
831 default:
832 stream.Printf("absurd: dt=%d",data_type);
833 break;
834 }
835 return true;
836 }
837 }
838 else
839 {
Enrico Granataf91e78f2012-09-13 18:27:09 +0000840 // similar to ExtractValueFromObjCExpression but uses summary instead of value
Enrico Granatacaaf0102012-09-04 18:48:21 +0000841 StreamString expr_path_stream;
842 valobj.GetExpressionPath(expr_path_stream, false);
843 StreamString expr;
844 expr.Printf("(NSString*)[%s stringValue]",expr_path_stream.GetData());
845 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
846 lldb::ValueObjectSP result_sp;
847 Target* target = exe_ctx.GetTargetPtr();
848 StackFrame* stack_frame = exe_ctx.GetFramePtr();
849 if (!target || !stack_frame)
850 return false;
Enrico Granatad27026e2012-09-05 20:41:26 +0000851
Jim Ingham47beabb2012-10-16 21:41:58 +0000852 EvaluateExpressionOptions options;
Enrico Granatad27026e2012-09-05 20:41:26 +0000853 options.SetCoerceToId(false)
854 .SetUnwindOnError(true)
855 .SetKeepInMemory(true)
856 .SetUseDynamic(lldb::eDynamicCanRunTarget);
857
Enrico Granatacaaf0102012-09-04 18:48:21 +0000858 target->EvaluateExpression(expr.GetData(),
859 stack_frame,
Enrico Granatad27026e2012-09-05 20:41:26 +0000860 result_sp,
861 options);
Enrico Granatacaaf0102012-09-04 18:48:21 +0000862 if (!result_sp)
863 return false;
864 stream.Printf("%s",result_sp->GetSummaryAsCString());
865 return true;
866 }
867}
868
869bool
Enrico Granataf91e78f2012-09-13 18:27:09 +0000870lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +0000871{
872 ProcessSP process_sp = valobj.GetProcessSP();
873 if (!process_sp)
874 return false;
875
876 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
877
878 if (!runtime)
879 return false;
880
881 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
882
883 if (!descriptor.get() || !descriptor->IsValid())
884 return false;
885
886 uint32_t ptr_size = process_sp->GetAddressByteSize();
887
888 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
889
890 if (!valobj_addr)
891 return false;
892
893 const char* class_name = descriptor->GetClassName().GetCString();
894
Enrico Granata25c9ade2012-09-29 00:45:53 +0000895 if (!class_name || !*class_name)
896 return false;
897
Enrico Granatacaaf0102012-09-04 18:48:21 +0000898 uint64_t info_bits_location = valobj_addr + ptr_size;
899 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
900 info_bits_location += 3;
901
902 Error error;
903
904 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
905 if (error.Fail())
906 return false;
907
908 bool is_mutable = (info_bits & 1) == 1;
909 bool is_inline = (info_bits & 0x60) == 0;
910 bool has_explicit_length = (info_bits & (1 | 4)) != 4;
911 bool is_unicode = (info_bits & 0x10) == 0x10;
912 bool is_special = strcmp(class_name,"NSPathStore2") == 0;
913
914 if (strcmp(class_name,"NSString") &&
915 strcmp(class_name,"CFStringRef") &&
916 strcmp(class_name,"CFMutableStringRef") &&
917 strcmp(class_name,"__NSCFConstantString") &&
918 strcmp(class_name,"__NSCFString") &&
919 strcmp(class_name,"NSCFConstantString") &&
920 strcmp(class_name,"NSCFString") &&
921 strcmp(class_name,"NSPathStore2"))
922 {
923 // probably not one of us - bail out
924 return false;
925 }
926
927 if (is_mutable)
928 {
929 uint64_t location = 2 * ptr_size + valobj_addr;
930 location = process_sp->ReadPointerFromMemory(location, error);
931 if (error.Fail())
932 return false;
933 if (has_explicit_length and is_unicode)
Enrico Granatacd8cd612013-01-14 23:53:26 +0000934 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@');
Enrico Granatacaaf0102012-09-04 18:48:21 +0000935 else
936 {
937 location++;
938 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
939 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
940 if (error.Fail())
941 return false;
942 if (data_read)
943 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
944 return true;
945 }
946 }
947 else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
948 {
949 uint64_t location = 3 * ptr_size + valobj_addr;
950 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
951 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
952 if (error.Fail())
953 return false;
954 if (data_read)
955 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
956 return true;
957 }
958 else if (is_unicode)
959 {
960 uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0);
961 if (is_inline)
962 {
963 if (!has_explicit_length)
964 {
965 stream.Printf("found new combo");
966 return true;
967 }
968 else
969 location += ptr_size;
970 }
971 else
972 {
973 location = process_sp->ReadPointerFromMemory(location, error);
974 if (error.Fail())
975 return false;
976 }
Enrico Granatacd8cd612013-01-14 23:53:26 +0000977 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
Enrico Granatacaaf0102012-09-04 18:48:21 +0000978 }
979 else if (is_special)
980 {
981 uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
Enrico Granatacd8cd612013-01-14 23:53:26 +0000982 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
Enrico Granatacaaf0102012-09-04 18:48:21 +0000983 }
984 else if (is_inline)
985 {
986 uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0);
987 if (!has_explicit_length)
988 location++;
989 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
990 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
991 if (error.Fail())
992 return false;
993 if (data_read)
994 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
995 return true;
996 }
997 else
998 {
999 uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0);
1000 location = process_sp->ReadPointerFromMemory(location, error);
1001 if (error.Fail())
1002 return false;
1003 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
1004 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
1005 if (error.Fail())
1006 return false;
1007 if (data_read)
1008 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
1009 return true;
1010 }
1011
1012 stream.Printf("class name = %s",class_name);
1013 return true;
1014
1015}
1016
Enrico Granata9abbfba2012-10-03 23:53:45 +00001017bool
1018lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
1019{
1020 stream.Printf("%s",valobj.GetObjectDescription());
1021 return true;
1022}
1023
Enrico Granatadb054912012-10-29 21:18:03 +00001024bool
1025lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
1026{
1027 const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(),
1028 valobj.GetClangAST(),
1029 NULL);
1030
1031 ValueObjectSP real_guy_sp = valobj.GetSP();
1032
1033 if (type_info & ClangASTContext::eTypeIsPointer)
1034 {
1035 Error err;
1036 real_guy_sp = valobj.Dereference(err);
1037 if (err.Fail() || !real_guy_sp)
1038 return false;
1039 }
1040 else if (type_info & ClangASTContext::eTypeIsReference)
1041 {
1042 real_guy_sp = valobj.GetChildAtIndex(0, true);
1043 if (!real_guy_sp)
1044 return false;
1045 }
1046 uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
1047 if (value == 0)
1048 {
1049 stream.Printf("NO");
1050 return true;
1051 }
1052 stream.Printf("YES");
1053 return true;
1054}
1055
1056template <bool is_sel_ptr>
1057bool
1058lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
1059{
1060 lldb::addr_t data_address = LLDB_INVALID_ADDRESS;
1061
1062 if (is_sel_ptr)
1063 data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1064 else
1065 data_address = valobj.GetAddressOf();
1066
1067 if (data_address == LLDB_INVALID_ADDRESS)
1068 return false;
1069
1070 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1071
1072 void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr();
1073 ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type));
1074
1075 ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar));
1076
1077 stream.Printf("%s",valobj_sp->GetSummaryAsCString());
1078 return true;
1079}
1080
Enrico Granataf91e78f2012-09-13 18:27:09 +00001081lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1082SyntheticChildrenFrontEnd(*valobj_sp.get()),
1083m_exe_ctx_ref(),
1084m_ptr_size(8),
1085m_data_32(NULL),
1086m_data_64(NULL)
1087{
Enrico Granata247da332012-10-04 21:04:46 +00001088 if (valobj_sp)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001089 {
Enrico Granata247da332012-10-04 21:04:46 +00001090 m_id_type = ClangASTType(valobj_sp->GetClangAST(),valobj_sp->GetClangAST()->ObjCBuiltinIdTy.getAsOpaquePtr());
1091 Update();
Enrico Granataf91e78f2012-09-13 18:27:09 +00001092 }
Enrico Granataf91e78f2012-09-13 18:27:09 +00001093}
1094
Greg Clayton36da2aa2013-01-25 18:06:21 +00001095size_t
Enrico Granataf91e78f2012-09-13 18:27:09 +00001096lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
1097{
1098 if (m_data_32)
1099 return m_data_32->_used;
1100 if (m_data_64)
1101 return m_data_64->_used;
1102 return 0;
1103}
1104
1105lldb::ValueObjectSP
Greg Clayton36da2aa2013-01-25 18:06:21 +00001106lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001107{
1108 if (!m_data_32 && !m_data_64)
1109 return lldb::ValueObjectSP();
1110 if (idx >= CalculateNumChildren())
1111 return lldb::ValueObjectSP();
1112 lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data);
1113 object_at_idx += (idx * m_ptr_size);
1114 StreamString idx_name;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001115 idx_name.Printf("[%zu]",idx);
Enrico Granataf91e78f2012-09-13 18:27:09 +00001116 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(),
1117 object_at_idx,
1118 m_exe_ctx_ref,
1119 m_id_type);
1120 m_children.push_back(retval_sp);
1121 return retval_sp;
1122}
1123
1124bool
1125lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update()
1126{
1127 m_children.clear();
Enrico Granata247da332012-10-04 21:04:46 +00001128 ValueObjectSP valobj_sp = m_backend.GetSP();
1129 m_ptr_size = 0;
1130 delete m_data_32;
1131 m_data_32 = NULL;
1132 delete m_data_64;
1133 m_data_64 = NULL;
1134 if (valobj_sp->IsDynamic())
1135 valobj_sp = valobj_sp->GetStaticValue();
1136 if (!valobj_sp)
1137 return false;
1138 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1139 Error error;
1140 if (valobj_sp->IsPointerType())
1141 {
1142 valobj_sp = valobj_sp->Dereference(error);
1143 if (error.Fail() || !valobj_sp)
1144 return false;
1145 }
1146 error.Clear();
1147 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1148 if (!process_sp)
1149 return false;
1150 m_ptr_size = process_sp->GetAddressByteSize();
1151 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1152 if (m_ptr_size == 4)
1153 {
1154 m_data_32 = new DataDescriptor_32();
1155 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
1156 }
1157 else
1158 {
1159 m_data_64 = new DataDescriptor_64();
1160 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
1161 }
1162 if (error.Fail())
1163 return false;
Enrico Granataf91e78f2012-09-13 18:27:09 +00001164 return false;
1165}
1166
Enrico Granata800332c2012-10-23 19:54:09 +00001167bool
1168lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
1169{
Enrico Granataf3c10482012-12-10 19:55:53 +00001170 return true;
Enrico Granata800332c2012-10-23 19:54:09 +00001171}
1172
Enrico Granataf91e78f2012-09-13 18:27:09 +00001173static uint32_t
1174ExtractIndexFromString (const char* item_name)
1175{
1176 if (!item_name || !*item_name)
1177 return UINT32_MAX;
1178 if (*item_name != '[')
1179 return UINT32_MAX;
1180 item_name++;
1181 uint32_t idx = 0;
1182 while(*item_name)
1183 {
1184 char x = *item_name;
1185 if (x == ']')
1186 break;
1187 if (x < '0' || x > '9')
1188 return UINT32_MAX;
1189 idx = 10*idx + (x-'0');
1190 item_name++;
1191 }
1192 return idx;
1193}
1194
Enrico Granataf509c5e2013-01-28 23:47:25 +00001195size_t
Enrico Granataf91e78f2012-09-13 18:27:09 +00001196lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1197{
1198 if (!m_data_32 && !m_data_64)
1199 return UINT32_MAX;
1200 const char* item_name = name.GetCString();
1201 uint32_t idx = ExtractIndexFromString(item_name);
1202 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1203 return UINT32_MAX;
1204 return idx;
1205}
1206
1207lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd ()
1208{
1209 delete m_data_32;
1210 m_data_32 = NULL;
1211 delete m_data_64;
1212 m_data_64 = NULL;
1213}
1214
1215lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1216SyntheticChildrenFrontEnd(*valobj_sp.get()),
1217m_exe_ctx_ref(),
1218m_ptr_size(8),
1219m_items(0),
1220m_data_ptr(0)
1221{
Enrico Granata247da332012-10-04 21:04:46 +00001222 if (valobj_sp)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001223 {
Enrico Granata247da332012-10-04 21:04:46 +00001224 m_id_type = ClangASTType(valobj_sp->GetClangAST(),valobj_sp->GetClangAST()->ObjCBuiltinIdTy.getAsOpaquePtr());
1225 Update();
Enrico Granataf91e78f2012-09-13 18:27:09 +00001226 }
Enrico Granataf91e78f2012-09-13 18:27:09 +00001227}
1228
1229lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd ()
1230{
1231}
1232
Enrico Granataf509c5e2013-01-28 23:47:25 +00001233size_t
Enrico Granataf91e78f2012-09-13 18:27:09 +00001234lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1235{
1236 const char* item_name = name.GetCString();
1237 uint32_t idx = ExtractIndexFromString(item_name);
1238 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1239 return UINT32_MAX;
1240 return idx;
1241}
1242
Greg Clayton36da2aa2013-01-25 18:06:21 +00001243size_t
Enrico Granataf91e78f2012-09-13 18:27:09 +00001244lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
1245{
1246 return m_items;
1247}
1248
1249bool
1250lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
1251{
Enrico Granata247da332012-10-04 21:04:46 +00001252 m_ptr_size = 0;
1253 m_items = 0;
1254 m_data_ptr = 0;
Enrico Granataf91e78f2012-09-13 18:27:09 +00001255 m_children.clear();
Enrico Granata247da332012-10-04 21:04:46 +00001256 ValueObjectSP valobj_sp = m_backend.GetSP();
1257 if (valobj_sp->IsDynamic())
1258 valobj_sp = valobj_sp->GetStaticValue();
1259 if (!valobj_sp)
1260 return false;
1261 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1262 Error error;
1263 if (valobj_sp->IsPointerType())
1264 {
1265 valobj_sp = valobj_sp->Dereference(error);
1266 if (error.Fail() || !valobj_sp)
1267 return false;
1268 }
1269 error.Clear();
1270 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1271 if (!process_sp)
1272 return false;
1273 m_ptr_size = process_sp->GetAddressByteSize();
1274 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1275 m_items = process_sp->ReadPointerFromMemory(data_location, error);
1276 if (error.Fail())
1277 return false;
1278 m_data_ptr = data_location+m_ptr_size;
Enrico Granataf91e78f2012-09-13 18:27:09 +00001279 return false;
1280}
1281
Enrico Granata800332c2012-10-23 19:54:09 +00001282bool
1283lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
1284{
Enrico Granataf3c10482012-12-10 19:55:53 +00001285 return true;
Enrico Granata800332c2012-10-23 19:54:09 +00001286}
1287
Enrico Granataf91e78f2012-09-13 18:27:09 +00001288lldb::ValueObjectSP
Greg Clayton36da2aa2013-01-25 18:06:21 +00001289lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001290{
1291 if (idx >= CalculateNumChildren())
1292 return lldb::ValueObjectSP();
1293 lldb::addr_t object_at_idx = m_data_ptr;
1294 object_at_idx += (idx * m_ptr_size);
1295 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1296 if (!process_sp)
1297 return lldb::ValueObjectSP();
1298 Error error;
1299 object_at_idx = process_sp->ReadPointerFromMemory(object_at_idx, error);
1300 if (error.Fail())
1301 return lldb::ValueObjectSP();
1302 StreamString expr;
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001303 expr.Printf("(id)%" PRIu64,object_at_idx);
Enrico Granataf91e78f2012-09-13 18:27:09 +00001304 StreamString idx_name;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001305 idx_name.Printf("[%zu]",idx);
Enrico Granataf91e78f2012-09-13 18:27:09 +00001306 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
1307 m_children.push_back(retval_sp);
1308 return retval_sp;
1309}
1310
1311SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
1312{
1313 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
1314 if (!process_sp)
1315 return NULL;
1316 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1317 if (!runtime)
1318 return NULL;
1319
1320 if (!valobj_sp->IsPointerType())
1321 {
1322 Error error;
1323 valobj_sp = valobj_sp->AddressOf(error);
1324 if (error.Fail() || !valobj_sp)
1325 return NULL;
1326 }
1327
1328 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
1329
1330 if (!descriptor.get() || !descriptor->IsValid())
1331 return NULL;
1332
1333 const char* class_name = descriptor->GetClassName().GetCString();
Enrico Granata7685a562012-09-29 00:47:43 +00001334
1335 if (!class_name || !*class_name)
1336 return NULL;
1337
Enrico Granataf91e78f2012-09-13 18:27:09 +00001338 if (!strcmp(class_name,"__NSArrayI"))
1339 {
1340 return (new NSArrayISyntheticFrontEnd(valobj_sp));
1341 }
1342 else if (!strcmp(class_name,"__NSArrayM"))
1343 {
1344 return (new NSArrayMSyntheticFrontEnd(valobj_sp));
1345 }
1346 else
1347 {
1348 return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp));
1349 }
1350}
1351
1352lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1353SyntheticChildrenFrontEnd(*valobj_sp.get())
1354{}
1355
Greg Clayton36da2aa2013-01-25 18:06:21 +00001356size_t
Enrico Granataf91e78f2012-09-13 18:27:09 +00001357lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
1358{
Enrico Granataf91e78f2012-09-13 18:27:09 +00001359 uint64_t count = 0;
1360 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
1361 return count;
1362 return 0;
1363}
1364
1365lldb::ValueObjectSP
Greg Clayton36da2aa2013-01-25 18:06:21 +00001366lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001367{
1368 StreamString idx_name;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001369 idx_name.Printf("[%zu]",idx);
Enrico Granataf91e78f2012-09-13 18:27:09 +00001370 lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
1371 if (valobj_sp)
1372 valobj_sp->SetName(ConstString(idx_name.GetData()));
1373 return valobj_sp;
1374}
1375
1376bool
1377lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update()
1378{
1379 return false;
1380}
1381
Enrico Granata800332c2012-10-23 19:54:09 +00001382bool
1383lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren ()
1384{
Enrico Granataf3c10482012-12-10 19:55:53 +00001385 return true;
Enrico Granata800332c2012-10-23 19:54:09 +00001386}
1387
Enrico Granataf509c5e2013-01-28 23:47:25 +00001388size_t
Enrico Granataf91e78f2012-09-13 18:27:09 +00001389lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1390{
1391 return 0;
1392}
1393
1394lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd ()
1395{}
1396
Enrico Granata3a08fd12012-09-18 17:43:16 +00001397SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
1398{
1399
1400 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
1401 if (!process_sp)
1402 return NULL;
1403 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1404 if (!runtime)
1405 return NULL;
1406
1407 if (!valobj_sp->IsPointerType())
1408 {
1409 Error error;
1410 valobj_sp = valobj_sp->AddressOf(error);
1411 if (error.Fail() || !valobj_sp)
1412 return NULL;
1413 }
1414
1415 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
1416
1417 if (!descriptor.get() || !descriptor->IsValid())
1418 return NULL;
1419
1420 const char* class_name = descriptor->GetClassName().GetCString();
Enrico Granata7685a562012-09-29 00:47:43 +00001421
1422 if (!class_name || !*class_name)
1423 return NULL;
1424
Enrico Granata3a08fd12012-09-18 17:43:16 +00001425 if (!strcmp(class_name,"__NSDictionaryI"))
1426 {
1427 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
1428 }
1429 else if (!strcmp(class_name,"__NSDictionaryM"))
1430 {
1431 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
1432 }
1433 else
1434 {
1435 return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp));
1436 }
1437}
1438
1439lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1440SyntheticChildrenFrontEnd(*valobj_sp.get())
1441{}
1442
Greg Clayton36da2aa2013-01-25 18:06:21 +00001443size_t
Enrico Granata3a08fd12012-09-18 17:43:16 +00001444lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
1445{
1446 uint64_t count = 0;
1447 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
1448 return count;
1449 return 0;
1450}
1451
1452lldb::ValueObjectSP
Greg Clayton36da2aa2013-01-25 18:06:21 +00001453lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
Enrico Granata3a08fd12012-09-18 17:43:16 +00001454{
1455 StreamString idx_name;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001456 idx_name.Printf("[%zu]",idx);
Enrico Granata3a08fd12012-09-18 17:43:16 +00001457 StreamString valobj_expr_path;
1458 m_backend.GetExpressionPath(valobj_expr_path, false);
1459 StreamString key_fetcher_expr;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001460 key_fetcher_expr.Printf("(id)[(NSArray*)[%s allKeys] objectAtIndex:%zu]",valobj_expr_path.GetData(),idx);
Enrico Granata3a08fd12012-09-18 17:43:16 +00001461 StreamString value_fetcher_expr;
1462 value_fetcher_expr.Printf("(id)[%s objectForKey:%s]",valobj_expr_path.GetData(),key_fetcher_expr.GetData());
1463 StreamString object_fetcher_expr;
Enrico Granatafd3d28d2012-10-01 21:49:10 +00001464 object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData());
Enrico Granata3a08fd12012-09-18 17:43:16 +00001465 lldb::ValueObjectSP child_sp;
1466 m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
Jim Ingham47beabb2012-10-16 21:41:58 +00001467 EvaluateExpressionOptions().SetKeepInMemory(true));
Enrico Granata3a08fd12012-09-18 17:43:16 +00001468 if (child_sp)
1469 child_sp->SetName(ConstString(idx_name.GetData()));
1470 return child_sp;
1471}
1472
1473bool
1474lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
1475{
1476 return false;
1477}
1478
Enrico Granata800332c2012-10-23 19:54:09 +00001479bool
1480lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
1481{
Enrico Granataf3c10482012-12-10 19:55:53 +00001482 return true;
Enrico Granata800332c2012-10-23 19:54:09 +00001483}
1484
Enrico Granataf509c5e2013-01-28 23:47:25 +00001485size_t
Enrico Granata3a08fd12012-09-18 17:43:16 +00001486lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1487{
1488 return 0;
1489}
1490
1491lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
1492{}
1493
1494lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1495 SyntheticChildrenFrontEnd(*valobj_sp.get()),
1496 m_exe_ctx_ref(),
1497 m_ptr_size(8),
1498 m_data_32(NULL),
1499 m_data_64(NULL)
1500{
Enrico Granataa787c1a2012-10-04 21:46:06 +00001501 if (valobj_sp)
1502 Update();
Enrico Granata3a08fd12012-09-18 17:43:16 +00001503}
1504
1505lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
1506{
1507 delete m_data_32;
1508 m_data_32 = NULL;
1509 delete m_data_64;
1510 m_data_64 = NULL;
1511}
1512
Enrico Granataf509c5e2013-01-28 23:47:25 +00001513size_t
Enrico Granata3a08fd12012-09-18 17:43:16 +00001514lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1515{
1516 const char* item_name = name.GetCString();
1517 uint32_t idx = ExtractIndexFromString(item_name);
1518 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1519 return UINT32_MAX;
1520 return idx;
1521}
1522
Greg Clayton36da2aa2013-01-25 18:06:21 +00001523size_t
Enrico Granata3a08fd12012-09-18 17:43:16 +00001524lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
1525{
1526 if (!m_data_32 && !m_data_64)
1527 return 0;
1528 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1529}
1530
1531bool
1532lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
1533{
1534 m_children.clear();
Enrico Granataa787c1a2012-10-04 21:46:06 +00001535 delete m_data_32;
1536 m_data_32 = NULL;
1537 delete m_data_64;
1538 m_data_64 = NULL;
1539 m_ptr_size = 0;
1540 ValueObjectSP valobj_sp = m_backend.GetSP();
1541 if (!valobj_sp)
1542 return false;
1543 if (valobj_sp->IsDynamic())
1544 valobj_sp = valobj_sp->GetStaticValue();
1545 if (!valobj_sp)
1546 return false;
1547 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1548 Error error;
1549 if (valobj_sp->IsPointerType())
1550 {
1551 valobj_sp = valobj_sp->Dereference(error);
1552 if (error.Fail() || !valobj_sp)
1553 return false;
1554 }
1555 error.Clear();
1556 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1557 if (!process_sp)
1558 return false;
1559 m_ptr_size = process_sp->GetAddressByteSize();
1560 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1561 if (m_ptr_size == 4)
1562 {
1563 m_data_32 = new DataDescriptor_32();
1564 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
1565 }
1566 else
1567 {
1568 m_data_64 = new DataDescriptor_64();
1569 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
1570 }
1571 if (error.Fail())
1572 return false;
1573 m_data_ptr = data_location + m_ptr_size;
Enrico Granata3a08fd12012-09-18 17:43:16 +00001574 return false;
1575}
1576
Enrico Granata800332c2012-10-23 19:54:09 +00001577bool
1578lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
1579{
Enrico Granataf3c10482012-12-10 19:55:53 +00001580 return true;
Enrico Granata800332c2012-10-23 19:54:09 +00001581}
1582
Enrico Granata3a08fd12012-09-18 17:43:16 +00001583lldb::ValueObjectSP
Greg Clayton36da2aa2013-01-25 18:06:21 +00001584lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
Enrico Granata3a08fd12012-09-18 17:43:16 +00001585{
1586 uint32_t num_children = CalculateNumChildren();
1587
1588 if (idx >= num_children)
1589 return lldb::ValueObjectSP();
1590
1591 if (m_children.empty())
1592 {
1593 // do the scan phase
1594 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1595
1596 uint32_t tries = 0;
1597 uint32_t test_idx = 0;
1598
1599 while(tries < num_children)
1600 {
1601 key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
1602 val_at_idx = key_at_idx + m_ptr_size;
1603 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1604 if (!process_sp)
1605 return lldb::ValueObjectSP();
1606 Error error;
1607 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1608 if (error.Fail())
1609 return lldb::ValueObjectSP();
1610 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1611 if (error.Fail())
1612 return lldb::ValueObjectSP();
1613
1614 test_idx++;
1615
1616 if (!key_at_idx || !val_at_idx)
1617 continue;
1618 tries++;
1619
1620 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
1621
1622 m_children.push_back(descriptor);
1623 }
1624 }
1625
1626 if (idx >= m_children.size()) // should never happen
1627 return lldb::ValueObjectSP();
1628
1629 DictionaryItemDescriptor &dict_item = m_children[idx];
1630 if (!dict_item.valobj_sp)
1631 {
1632 // make the new ValueObject
1633 StreamString expr;
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001634 expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr);
Enrico Granata3a08fd12012-09-18 17:43:16 +00001635 StreamString idx_name;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001636 idx_name.Printf("[%zu]",idx);
Enrico Granata3a08fd12012-09-18 17:43:16 +00001637 dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
1638 }
1639 return dict_item.valobj_sp;
1640}
1641
1642lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1643 SyntheticChildrenFrontEnd(*valobj_sp.get()),
1644 m_exe_ctx_ref(),
1645 m_ptr_size(8),
1646 m_data_32(NULL),
1647 m_data_64(NULL)
1648{
Enrico Granataa787c1a2012-10-04 21:46:06 +00001649 if (valobj_sp)
1650 Update ();
Enrico Granata3a08fd12012-09-18 17:43:16 +00001651}
1652
1653lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
1654{
1655 delete m_data_32;
1656 m_data_32 = NULL;
1657 delete m_data_64;
1658 m_data_64 = NULL;
1659}
1660
Enrico Granataf509c5e2013-01-28 23:47:25 +00001661size_t
Enrico Granata3a08fd12012-09-18 17:43:16 +00001662lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1663{
1664 const char* item_name = name.GetCString();
1665 uint32_t idx = ExtractIndexFromString(item_name);
1666 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1667 return UINT32_MAX;
1668 return idx;
1669}
1670
Greg Clayton36da2aa2013-01-25 18:06:21 +00001671size_t
Enrico Granata3a08fd12012-09-18 17:43:16 +00001672lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
1673{
1674 if (!m_data_32 && !m_data_64)
1675 return 0;
1676 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1677}
1678
1679bool
1680lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
1681{
1682 m_children.clear();
Enrico Granataa787c1a2012-10-04 21:46:06 +00001683 ValueObjectSP valobj_sp = m_backend.GetSP();
1684 m_ptr_size = 0;
1685 delete m_data_32;
1686 m_data_32 = NULL;
1687 delete m_data_64;
1688 m_data_64 = NULL;
1689 if (!valobj_sp)
1690 return false;
1691 if (valobj_sp->IsDynamic())
1692 valobj_sp = valobj_sp->GetStaticValue();
1693 if (!valobj_sp)
1694 return false;
1695 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1696 Error error;
1697 if (valobj_sp->IsPointerType())
1698 {
1699 valobj_sp = valobj_sp->Dereference(error);
1700 if (error.Fail() || !valobj_sp)
1701 return false;
1702 }
1703 error.Clear();
1704 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1705 if (!process_sp)
1706 return false;
1707 m_ptr_size = process_sp->GetAddressByteSize();
1708 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1709 if (m_ptr_size == 4)
1710 {
1711 m_data_32 = new DataDescriptor_32();
1712 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
1713 }
1714 else
1715 {
1716 m_data_64 = new DataDescriptor_64();
1717 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
1718 }
1719 if (error.Fail())
1720 return false;
Enrico Granata3a08fd12012-09-18 17:43:16 +00001721 return false;
1722}
1723
Enrico Granata800332c2012-10-23 19:54:09 +00001724bool
1725lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
1726{
Enrico Granataf3c10482012-12-10 19:55:53 +00001727 return true;
Enrico Granata800332c2012-10-23 19:54:09 +00001728}
1729
Enrico Granata3a08fd12012-09-18 17:43:16 +00001730lldb::ValueObjectSP
Greg Clayton36da2aa2013-01-25 18:06:21 +00001731lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
Enrico Granata3a08fd12012-09-18 17:43:16 +00001732{
1733 lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1734 lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1735
1736 uint32_t num_children = CalculateNumChildren();
1737
1738 if (idx >= num_children)
1739 return lldb::ValueObjectSP();
1740
1741 if (m_children.empty())
1742 {
1743 // do the scan phase
1744 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1745
1746 uint32_t tries = 0;
1747 uint32_t test_idx = 0;
1748
1749 while(tries < num_children)
1750 {
1751 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1752 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
1753 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1754 if (!process_sp)
1755 return lldb::ValueObjectSP();
1756 Error error;
1757 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1758 if (error.Fail())
1759 return lldb::ValueObjectSP();
1760 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1761 if (error.Fail())
1762 return lldb::ValueObjectSP();
1763
1764 test_idx++;
1765
1766 if (!key_at_idx || !val_at_idx)
1767 continue;
1768 tries++;
1769
1770 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
1771
1772 m_children.push_back(descriptor);
1773 }
1774 }
1775
1776 if (idx >= m_children.size()) // should never happen
1777 return lldb::ValueObjectSP();
1778
1779 DictionaryItemDescriptor &dict_item = m_children[idx];
1780 if (!dict_item.valobj_sp)
1781 {
1782 // make the new ValueObject
1783 StreamString expr;
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001784 expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr);
Enrico Granata3a08fd12012-09-18 17:43:16 +00001785 StreamString idx_name;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001786 idx_name.Printf("[%zu]",idx);
Enrico Granata3a08fd12012-09-18 17:43:16 +00001787 dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
1788 }
1789 return dict_item.valobj_sp;
1790}
Enrico Granatacaaf0102012-09-04 18:48:21 +00001791
1792template bool
Enrico Granataf91e78f2012-09-13 18:27:09 +00001793lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
Enrico Granatacaaf0102012-09-04 18:48:21 +00001794
1795template bool
Enrico Granataf91e78f2012-09-13 18:27:09 +00001796lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;
Enrico Granatacaaf0102012-09-04 18:48:21 +00001797
1798template bool
Enrico Granataf91e78f2012-09-13 18:27:09 +00001799lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
1800
1801template bool
1802lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
Enrico Granatadb054912012-10-29 21:18:03 +00001803
1804template bool
1805lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
1806
1807template bool
1808lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;