blob: 2df6524c365e5d9479827a64254825af24eadaee [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 Granatacba09f62013-03-19 00:27:22 +000012#include <time.h>
13
Enrico Granataf509c5e2013-01-28 23:47:25 +000014#include "lldb/DataFormatters/CXXFormatterFunctions.h"
Enrico Granatacaaf0102012-09-04 18:48:21 +000015
Dmitri Gribenko2a64f9a2013-01-30 15:05:59 +000016#include "llvm/Support/ConvertUTF.h"
Enrico Granatacaaf0102012-09-04 18:48:21 +000017
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 Granataea687532013-02-15 23:38:37 +000066bool
67lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
68 const char* target_type,
69 const char* selector,
70 Stream &stream)
71{
72 if (!target_type || !*target_type)
73 return false;
74 if (!selector || !*selector)
75 return false;
76 StreamString expr;
Enrico Granata04d3bb22013-02-19 01:14:06 +000077 expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
Enrico Granataea687532013-02-15 23:38:37 +000078 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
79 lldb::ValueObjectSP result_sp;
80 Target* target = exe_ctx.GetTargetPtr();
81 StackFrame* stack_frame = exe_ctx.GetFramePtr();
82 if (!target || !stack_frame)
83 return false;
84
85 EvaluateExpressionOptions options;
86 options.SetCoerceToId(false)
87 .SetUnwindOnError(true)
88 .SetKeepInMemory(true)
89 .SetUseDynamic(lldb::eDynamicCanRunTarget);
90
91 target->EvaluateExpression(expr.GetData(),
92 stack_frame,
93 result_sp,
94 options);
95 if (!result_sp)
96 return false;
97 stream.Printf("%s",result_sp->GetSummaryAsCString());
98 return true;
99}
100
Enrico Granataf91e78f2012-09-13 18:27:09 +0000101lldb::ValueObjectSP
102lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
103 const char* return_type,
104 const char* selector,
105 uint64_t index)
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 StreamString expr_path_stream;
113 valobj.GetExpressionPath(expr_path_stream, false);
114 StreamString expr;
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000115 expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index);
Enrico Granataf91e78f2012-09-13 18:27:09 +0000116 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
117 lldb::ValueObjectSP result_sp;
118 Target* target = exe_ctx.GetTargetPtr();
119 StackFrame* stack_frame = exe_ctx.GetFramePtr();
120 if (!target || !stack_frame)
121 return valobj_sp;
122
Jim Ingham47beabb2012-10-16 21:41:58 +0000123 EvaluateExpressionOptions options;
Enrico Granataf91e78f2012-09-13 18:27:09 +0000124 options.SetCoerceToId(false)
125 .SetUnwindOnError(true)
126 .SetKeepInMemory(true)
127 .SetUseDynamic(lldb::eDynamicCanRunTarget);
128
129 target->EvaluateExpression(expr.GetData(),
130 stack_frame,
131 valobj_sp,
132 options);
133 return valobj_sp;
134}
135
136lldb::ValueObjectSP
137lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
138 const char* return_type,
139 const char* selector,
140 const char* key)
141{
142 lldb::ValueObjectSP valobj_sp;
143 if (!return_type || !*return_type)
144 return valobj_sp;
145 if (!selector || !*selector)
146 return valobj_sp;
147 if (!key || !*key)
148 return valobj_sp;
149 StreamString expr_path_stream;
150 valobj.GetExpressionPath(expr_path_stream, false);
151 StreamString expr;
152 expr.Printf("(%s)[%s %s:%s]",return_type,expr_path_stream.GetData(),selector,key);
153 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
154 lldb::ValueObjectSP result_sp;
155 Target* target = exe_ctx.GetTargetPtr();
156 StackFrame* stack_frame = exe_ctx.GetFramePtr();
157 if (!target || !stack_frame)
158 return valobj_sp;
159
Jim Ingham47beabb2012-10-16 21:41:58 +0000160 EvaluateExpressionOptions options;
Enrico Granataf91e78f2012-09-13 18:27:09 +0000161 options.SetCoerceToId(false)
162 .SetUnwindOnError(true)
163 .SetKeepInMemory(true)
164 .SetUseDynamic(lldb::eDynamicCanRunTarget);
165
166 target->EvaluateExpression(expr.GetData(),
167 stack_frame,
168 valobj_sp,
169 options);
170 return valobj_sp;
171}
172
Enrico Granatacd8cd612013-01-14 23:53:26 +0000173// use this call if you already have an LLDB-side buffer for the data
174template<typename SourceDataType>
Enrico Granataf5545f92013-01-10 22:08:35 +0000175static bool
Enrico Granatacd8cd612013-01-14 23:53:26 +0000176DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
177 const SourceDataType*,
178 UTF8**,
179 UTF8*,
180 ConversionFlags),
181 DataExtractor& data,
182 Stream& stream,
183 char prefix_token = '@',
184 char quote = '"',
185 int sourceSize = 0)
Enrico Granataf5545f92013-01-10 22:08:35 +0000186{
Enrico Granatacd8cd612013-01-14 23:53:26 +0000187 if (prefix_token != 0)
188 stream.Printf("%c",prefix_token);
189 if (quote != 0)
190 stream.Printf("%c",quote);
191 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
Enrico Granataf5545f92013-01-10 22:08:35 +0000192 {
Enrico Granatacd8cd612013-01-14 23:53:26 +0000193 const int bufferSPSize = data.GetByteSize();
194 if (sourceSize == 0)
195 {
196 const int origin_encoding = 8*sizeof(SourceDataType);
Greg Clayton0cd33402013-02-08 21:59:34 +0000197 sourceSize = bufferSPSize/(origin_encoding / 4);
Enrico Granatacd8cd612013-01-14 23:53:26 +0000198 }
199
200 SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
Enrico Granataf5545f92013-01-10 22:08:35 +0000201 SourceDataType *data_end_ptr = data_ptr + sourceSize;
202
203 while (data_ptr < data_end_ptr)
204 {
205 if (!*data_ptr)
206 {
207 data_end_ptr = data_ptr;
208 break;
209 }
210 data_ptr++;
211 }
212
Enrico Granatacd8cd612013-01-14 23:53:26 +0000213 data_ptr = (SourceDataType*)data.GetDataStart();
Enrico Granataf5545f92013-01-10 22:08:35 +0000214
Enrico Granata06d58b02013-01-11 02:44:00 +0000215 lldb::DataBufferSP utf8_data_buffer_sp;
216 UTF8* utf8_data_ptr = nullptr;
217 UTF8* utf8_data_end_ptr = nullptr;
Enrico Granatacd8cd612013-01-14 23:53:26 +0000218
Enrico Granataf5545f92013-01-10 22:08:35 +0000219 if (ConvertFunction)
Enrico Granata06d58b02013-01-11 02:44:00 +0000220 {
221 utf8_data_buffer_sp.reset(new DataBufferHeap(bufferSPSize,0));
222 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
223 utf8_data_end_ptr = utf8_data_ptr + bufferSPSize;
Enrico Granataf5545f92013-01-10 22:08:35 +0000224 ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
Enrico Granata06d58b02013-01-11 02:44:00 +0000225 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
226 }
Enrico Granataf5545f92013-01-10 22:08:35 +0000227 else
228 {
229 // just copy the pointers - the cast is necessary to make the compiler happy
230 // but this should only happen if we are reading UTF8 data
231 utf8_data_ptr = (UTF8*)data_ptr;
232 utf8_data_end_ptr = (UTF8*)data_end_ptr;
233 }
234
Enrico Granatab6985792013-01-12 01:00:22 +0000235 // since we tend to accept partial data (and even partially malformed data)
236 // we might end up with no NULL terminator before the end_ptr
237 // hence we need to take a slower route and ensure we stay within boundaries
Enrico Granataf5545f92013-01-10 22:08:35 +0000238 for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
239 {
240 if (!*utf8_data_ptr)
241 break;
242 stream.Printf("%c",*utf8_data_ptr);
243 }
Enrico Granatacd8cd612013-01-14 23:53:26 +0000244 }
245 if (quote != 0)
246 stream.Printf("%c",quote);
247 return true;
248}
249
250template<typename SourceDataType>
251static bool
252ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
253 const SourceDataType*,
254 UTF8**,
255 UTF8*,
256 ConversionFlags),
257 uint64_t location,
258 const ProcessSP& process_sp,
259 Stream& stream,
260 char prefix_token = '@',
261 char quote = '"',
262 int sourceSize = 0)
263{
264 if (location == 0 || location == LLDB_INVALID_ADDRESS)
265 return false;
266 if (!process_sp)
267 return false;
268
269 const int origin_encoding = 8*sizeof(SourceDataType);
270 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
271 return false;
272 // if not UTF8, I need a conversion function to return proper UTF8
273 if (origin_encoding != 8 && !ConvertFunction)
274 return false;
275
276 if (sourceSize == 0)
277 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
278 const int bufferSPSize = sourceSize * (origin_encoding >> 2);
279
280 Error error;
281 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
282
283 if (!buffer_sp->GetBytes())
284 return false;
285
286 size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error);
287 if (error.Fail() || data_read == 0)
288 {
289 stream.Printf("unable to read data");
Enrico Granataf5545f92013-01-10 22:08:35 +0000290 return true;
291 }
Enrico Granatacd8cd612013-01-14 23:53:26 +0000292
293 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
294
295 return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize);
Enrico Granataf5545f92013-01-10 22:08:35 +0000296}
297
298bool
299lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
300{
301 ProcessSP process_sp = valobj.GetProcessSP();
302 if (!process_sp)
303 return false;
304
305 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
306
307 if (!valobj_addr)
308 return false;
309
Enrico Granatacd8cd612013-01-14 23:53:26 +0000310 if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr,
Enrico Granataf5545f92013-01-10 22:08:35 +0000311 process_sp,
312 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000313 'u'))
Enrico Granataf5545f92013-01-10 22:08:35 +0000314 {
315 stream.Printf("Summary Unavailable");
316 return true;
317 }
318
319 return true;
320}
321
322bool
323lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
324{
325 ProcessSP process_sp = valobj.GetProcessSP();
326 if (!process_sp)
327 return false;
328
329 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
330
331 if (!valobj_addr)
332 return false;
333
Enrico Granatacd8cd612013-01-14 23:53:26 +0000334 if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr,
Enrico Granataf5545f92013-01-10 22:08:35 +0000335 process_sp,
336 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000337 'U'))
Enrico Granataf5545f92013-01-10 22:08:35 +0000338 {
339 stream.Printf("Summary Unavailable");
340 return true;
341 }
342
343 return true;
344}
345
346bool
347lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
348{
Enrico Granata06d58b02013-01-11 02:44:00 +0000349 ProcessSP process_sp = valobj.GetProcessSP();
350 if (!process_sp)
351 return false;
352
Enrico Granatab6985792013-01-12 01:00:22 +0000353 lldb::addr_t data_addr = 0;
354
355 if (valobj.IsPointerType())
356 data_addr = valobj.GetValueAsUnsigned(0);
357 else if (valobj.IsArrayType())
358 data_addr = valobj.GetAddressOf();
Enrico Granata06d58b02013-01-11 02:44:00 +0000359
Enrico Granatab6985792013-01-12 01:00:22 +0000360 if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
Enrico Granata06d58b02013-01-11 02:44:00 +0000361 return false;
362
363 clang::ASTContext* ast = valobj.GetClangAST();
364
365 if (!ast)
366 return false;
367
368 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
369
370 switch (wchar_size)
371 {
372 case 8:
373 // utf 8
Enrico Granatacd8cd612013-01-14 23:53:26 +0000374 return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr,
Enrico Granata06d58b02013-01-11 02:44:00 +0000375 process_sp,
376 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000377 'L');
Enrico Granata06d58b02013-01-11 02:44:00 +0000378 case 16:
379 // utf 16
Enrico Granatacd8cd612013-01-14 23:53:26 +0000380 return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr,
Enrico Granata06d58b02013-01-11 02:44:00 +0000381 process_sp,
382 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000383 'L');
Enrico Granata06d58b02013-01-11 02:44:00 +0000384 case 32:
385 // utf 32
Enrico Granatacd8cd612013-01-14 23:53:26 +0000386 return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr,
Enrico Granata06d58b02013-01-11 02:44:00 +0000387 process_sp,
388 stream,
Enrico Granatacd8cd612013-01-14 23:53:26 +0000389 'L');
390 default:
391 stream.Printf("size for wchar_t is not valid");
392 return true;
393 }
394 return true;
395}
396
397bool
398lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
399{
400 DataExtractor data;
401 valobj.GetData(data);
402
403 std::string value;
404 valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
405 if (!value.empty())
406 stream.Printf("%s ", value.c_str());
407
408 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
409}
410
411bool
412lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
413{
414 DataExtractor data;
415 valobj.GetData(data);
416
417 std::string value;
418 valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
419 if (!value.empty())
420 stream.Printf("%s ", value.c_str());
421
422 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
423}
424
425bool
426lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
427{
428 DataExtractor data;
429 valobj.GetData(data);
430
431 clang::ASTContext* ast = valobj.GetClangAST();
432
433 if (!ast)
434 return false;
435
436 std::string value;
437
438 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
439
440 switch (wchar_size)
441 {
442 case 8:
443 // utf 8
444 valobj.GetValueAsCString(lldb::eFormatChar, value);
445 if (!value.empty())
446 stream.Printf("%s ", value.c_str());
447 return DumpUTFBufferToStream<UTF8>(nullptr,
448 data,
449 stream,
450 'L',
451 '\'',
452 1);
453 case 16:
454 // utf 16
455 valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
456 if (!value.empty())
457 stream.Printf("%s ", value.c_str());
458 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
459 data,
460 stream,
461 'L',
462 '\'',
463 1);
464 case 32:
465 // utf 32
466 valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
467 if (!value.empty())
468 stream.Printf("%s ", value.c_str());
469 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
470 data,
471 stream,
472 'L',
473 '\'',
474 1);
Enrico Granata06d58b02013-01-11 02:44:00 +0000475 default:
476 stream.Printf("size for wchar_t is not valid");
477 return true;
478 }
479 return true;
Enrico Granataf5545f92013-01-10 22:08:35 +0000480}
481
Enrico Granatab6985792013-01-12 01:00:22 +0000482// this function extracts information from a libcxx std::basic_string<>
483// irregardless of template arguments. it reports the size (in item count not bytes)
484// and the location in memory where the string data can be found
485static bool
486ExtractLibcxxStringInfo (ValueObject& valobj,
487 ValueObjectSP &location_sp,
488 uint64_t& size)
489{
490 ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
491 if (!D)
492 return false;
493
494 ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
495 if (!size_mode)
496 return false;
497
498 uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0));
499
500 if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline
501 {
502 ValueObjectSP s(D->GetChildAtIndex(1, true));
503 if (!s)
504 return false;
505 size = ((size_mode_value >> 1) % 256);
506 location_sp = s->GetChildAtIndex(1, true);
507 return (location_sp.get() != nullptr);
508 }
509 else
510 {
511 ValueObjectSP l(D->GetChildAtIndex(0, true));
512 if (!l)
513 return false;
514 location_sp = l->GetChildAtIndex(2, true);
515 ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
516 if (!size_vo || !location_sp)
517 return false;
518 size = size_vo->GetValueAsUnsigned(0);
519 return true;
520 }
521}
522
523bool
524lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
525{
526 uint64_t size = 0;
527 ValueObjectSP location_sp((ValueObject*)nullptr);
528 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
529 return false;
530 if (size == 0)
531 {
532 stream.Printf("L\"\"");
533 return true;
534 }
535 if (!location_sp)
536 return false;
537 return WCharStringSummaryProvider(*location_sp.get(), stream);
538}
539
540bool
541lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
542{
543 uint64_t size = 0;
544 ValueObjectSP location_sp((ValueObject*)nullptr);
545 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
546 return false;
547 if (size == 0)
548 {
549 stream.Printf("\"\"");
550 return true;
551 }
552 if (!location_sp)
553 return false;
554 Error error;
Enrico Granata32d7ee32013-02-21 19:57:10 +0000555 if (location_sp->ReadPointedString(stream,
556 error,
557 0, // max length is decided by the settings
558 false) == 0) // do not honor array (terminates on first 0 byte even for a char[])
559 stream.Printf("\"\""); // if nothing was read, print an empty string
Enrico Granatab6985792013-01-12 01:00:22 +0000560 return error.Success();
561}
562
Enrico Granata280b30f2013-03-15 18:55:30 +0000563bool
564lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream)
565{
566 ProcessSP process_sp = valobj.GetProcessSP();
567 if (!process_sp)
568 return false;
569
570 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
571
572 if (!runtime)
573 return false;
574
575 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj.GetValueAsUnsigned(0)));
576
577 if (!descriptor.get() || !descriptor->IsValid())
578 return false;
579
580 const char* class_name = descriptor->GetClassName().GetCString();
581
582 if (!class_name || !*class_name)
583 return false;
584
585 stream.Printf("%s",class_name);
586 return true;
587}
588
Enrico Granatacaaf0102012-09-04 18:48:21 +0000589template<bool needs_at>
590bool
Enrico Granataf91e78f2012-09-13 18:27:09 +0000591lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +0000592{
593 ProcessSP process_sp = valobj.GetProcessSP();
594 if (!process_sp)
595 return false;
596
597 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
598
599 if (!runtime)
600 return false;
601
602 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
603
604 if (!descriptor.get() || !descriptor->IsValid())
605 return false;
606
607 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
608 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
609
610 if (!valobj_addr)
611 return false;
612
613 uint64_t value = 0;
614
615 const char* class_name = descriptor->GetClassName().GetCString();
Enrico Granata7685a562012-09-29 00:47:43 +0000616
617 if (!class_name || !*class_name)
618 return false;
619
Enrico Granatacaaf0102012-09-04 18:48:21 +0000620 if (!strcmp(class_name,"NSConcreteData") ||
621 !strcmp(class_name,"NSConcreteMutableData") ||
622 !strcmp(class_name,"__NSCFData"))
623 {
624 uint32_t offset = (is_64bit ? 16 : 8);
625 Error error;
626 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
627 if (error.Fail())
628 return false;
629 }
630 else
631 {
Enrico Granataf91e78f2012-09-13 18:27:09 +0000632 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
Enrico Granatacaaf0102012-09-04 18:48:21 +0000633 return false;
634 }
635
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000636 stream.Printf("%s%" PRIu64 " byte%s%s",
Enrico Granatacaaf0102012-09-04 18:48:21 +0000637 (needs_at ? "@\"" : ""),
638 value,
639 (value > 1 ? "s" : ""),
640 (needs_at ? "\"" : ""));
641
642 return true;
643}
644
645bool
Enrico Granatab70c6ef2013-03-15 18:44:08 +0000646lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream)
647{
648 ProcessSP process_sp = valobj.GetProcessSP();
649 if (!process_sp)
650 return false;
651
652 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
653
654 if (!runtime)
655 return false;
656
657 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
658
659 if (!descriptor.get() || !descriptor->IsValid())
660 return false;
661
662 uint32_t ptr_size = process_sp->GetAddressByteSize();
663
664 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
665
666 if (!valobj_addr)
667 return false;
668
669 const char* class_name = descriptor->GetClassName().GetCString();
670
671 if (!class_name || !*class_name)
672 return false;
673
674 if (!strcmp(class_name,"NSBundle"))
675 {
676 uint64_t offset = 5 * ptr_size;
677 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
678 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true));
679 StreamString summary_stream;
680 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
681 if (was_nsstring_ok && summary_stream.GetSize() > 0)
682 {
683 stream.Printf("%s",summary_stream.GetData());
684 return true;
685 }
686 }
687 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
688 // which is encoded differently and needs to be handled by running code
689 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream);
690}
691
692bool
Enrico Granata5782dae2013-03-16 01:50:07 +0000693lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream)
694{
695 ProcessSP process_sp = valobj.GetProcessSP();
696 if (!process_sp)
697 return false;
698
699 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
700
701 if (!runtime)
702 return false;
703
704 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
705
706 if (!descriptor.get() || !descriptor->IsValid())
707 return false;
708
709 uint32_t ptr_size = process_sp->GetAddressByteSize();
710
711 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
712
713 if (!valobj_addr)
714 return false;
715
716 const char* class_name = descriptor->GetClassName().GetCString();
717
718 if (!class_name || !*class_name)
719 return false;
720
721 if (!strcmp(class_name,"__NSTimeZone"))
722 {
723 uint64_t offset = ptr_size;
724 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
725 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true));
726 StreamString summary_stream;
727 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
728 if (was_nsstring_ok && summary_stream.GetSize() > 0)
729 {
730 stream.Printf("%s",summary_stream.GetData());
731 return true;
732 }
733 }
734 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
735}
736
737bool
Enrico Granatadc1df6b2013-03-16 00:50:25 +0000738lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream)
739{
740 ProcessSP process_sp = valobj.GetProcessSP();
741 if (!process_sp)
742 return false;
743
744 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
745
746 if (!runtime)
747 return false;
748
749 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
750
751 if (!descriptor.get() || !descriptor->IsValid())
752 return false;
753
754 uint32_t ptr_size = process_sp->GetAddressByteSize();
755
756 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
757
758 if (!valobj_addr)
759 return false;
760
761 const char* class_name = descriptor->GetClassName().GetCString();
762
763 if (!class_name || !*class_name)
764 return false;
765
766 if (!strcmp(class_name,"NSConcreteNotification"))
767 {
768 uint64_t offset = ptr_size;
769 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
770 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true));
771 StreamString summary_stream;
772 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
773 if (was_nsstring_ok && summary_stream.GetSize() > 0)
774 {
775 stream.Printf("%s",summary_stream.GetData());
776 return true;
777 }
778 }
779 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
780 // which is encoded differently and needs to be handled by running code
781 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
782}
783
784bool
785lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream)
786{
787 ProcessSP process_sp = valobj.GetProcessSP();
788 if (!process_sp)
789 return false;
790
791 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
792
793 if (!runtime)
794 return false;
795
796 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
797
798 if (!descriptor.get() || !descriptor->IsValid())
799 return false;
800
801 uint32_t ptr_size = process_sp->GetAddressByteSize();
802
803 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
804
805 if (!valobj_addr)
806 return false;
807
808 const char* class_name = descriptor->GetClassName().GetCString();
809
810 if (!class_name || !*class_name)
811 return false;
812
813 uint64_t port_number = 0;
814
815 do
816 {
817 if (!strcmp(class_name,"NSMachPort"))
818 {
819 uint64_t offset = (ptr_size == 4 ? 12 : 20);
820 Error error;
821 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
822 if (error.Success())
823 break;
824 }
825 if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
826 return false;
827 } while (false);
828
829 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
830 return true;
831}
832
833bool
Enrico Granatab70c6ef2013-03-15 18:44:08 +0000834lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream)
835{
836 ProcessSP process_sp = valobj.GetProcessSP();
837 if (!process_sp)
838 return false;
839
840 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
841
842 if (!runtime)
843 return false;
844
845 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
846
847 if (!descriptor.get() || !descriptor->IsValid())
848 return false;
849
850 uint32_t ptr_size = process_sp->GetAddressByteSize();
851
852 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
853
854 if (!valobj_addr)
855 return false;
856
857 uint32_t count = 0;
858
859 bool is_type_ok = false; // check to see if this is a CFBag we know about
860 if (descriptor->IsCFType())
861 {
862 ConstString type_name(valobj.GetTypeName());
863 if (type_name == ConstString("__CFBag") || type_name == ConstString("const struct __CFBag"))
864 {
865 if (valobj.IsPointerType())
866 is_type_ok = true;
867 }
868 }
869
870 if (is_type_ok == false)
871 {
Enrico Granatab70c6ef2013-03-15 18:44:08 +0000872 StackFrameSP frame_sp(valobj.GetFrameSP());
873 if (!frame_sp)
874 return false;
875 ValueObjectSP count_sp;
876 StreamString expr;
877 expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
878 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
879 return false;
880 if (!count_sp)
881 return false;
882 count = count_sp->GetValueAsUnsigned(0);
883 }
884 else
885 {
886 uint32_t offset = 2*ptr_size+4 + valobj_addr;
887 Error error;
888 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
889 if (error.Fail())
890 return false;
891 }
892 stream.Printf("@\"%u value%s\"",
893 count,(count == 1 ? "" : "s"));
894 return true;
895}
896
897bool
Enrico Granata5782dae2013-03-16 01:50:07 +0000898lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream)
899{
900 ProcessSP process_sp = valobj.GetProcessSP();
901 if (!process_sp)
902 return false;
903
904 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
905
906 if (!runtime)
907 return false;
908
909 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
910
911 if (!descriptor.get() || !descriptor->IsValid())
912 return false;
913
914 uint32_t ptr_size = process_sp->GetAddressByteSize();
915
916 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
917
918 if (!valobj_addr)
919 return false;
920
921 uint32_t count = 0;
922
923 bool is_type_ok = false; // check to see if this is a CFBag we know about
924 if (descriptor->IsCFType())
925 {
926 ConstString type_name(valobj.GetTypeName());
927 if (type_name == ConstString("__CFMutableBitVector") || type_name == ConstString("__CFBitVector") || type_name == ConstString("CFMutableBitVectorRef") || type_name == ConstString("CFBitVectorRef"))
928 {
929 if (valobj.IsPointerType())
930 is_type_ok = true;
931 }
932 }
933
934 if (is_type_ok == false)
935 return false;
936
937 Error error;
938 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
939 if (error.Fail())
940 return false;
941 uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
942 addr_t data_ptr = process_sp->ReadPointerFromMemory(valobj_addr+2*ptr_size+2*ptr_size, error);
943 if (error.Fail())
944 return false;
945 // make sure we do not try to read huge amounts of data
946 if (num_bytes > 1024)
947 num_bytes = 1024;
948 DataBufferSP buffer_sp(new DataBufferHeap(num_bytes,0));
949 num_bytes = process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
950 if (error.Fail())
951 return false;
952 for (int byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
953 {
954 uint8_t byte = buffer_sp->GetBytes()[byte_idx];
955 bool bit0 = (byte & 1) == 1;
956 bool bit1 = (byte & 2) == 2;
957 bool bit2 = (byte & 4) == 4;
958 bool bit3 = (byte & 8) == 8;
959 bool bit4 = (byte & 16) == 16;
960 bool bit5 = (byte & 32) == 32;
961 bool bit6 = (byte & 64) == 64;
962 bool bit7 = (byte & 128) == 128;
963 stream.Printf("%c%c%c%c %c%c%c%c ",
964 (bit7 ? '1' : '0'),
965 (bit6 ? '1' : '0'),
966 (bit5 ? '1' : '0'),
967 (bit4 ? '1' : '0'),
968 (bit3 ? '1' : '0'),
969 (bit2 ? '1' : '0'),
970 (bit1 ? '1' : '0'),
971 (bit0 ? '1' : '0'));
972 count -= 8;
973 }
974 {
975 // print the last byte ensuring we do not print spurious bits
976 uint8_t byte = buffer_sp->GetBytes()[num_bytes-1];
977 bool bit0 = (byte & 1) == 1;
978 bool bit1 = (byte & 2) == 2;
979 bool bit2 = (byte & 4) == 4;
980 bool bit3 = (byte & 8) == 8;
981 bool bit4 = (byte & 16) == 16;
982 bool bit5 = (byte & 32) == 32;
983 bool bit6 = (byte & 64) == 64;
984 bool bit7 = (byte & 128) == 128;
985 if (count)
986 {
987 stream.Printf("%c",bit7 ? '1' : '0');
988 count -= 1;
989 }
990 if (count)
991 {
992 stream.Printf("%c",bit6 ? '1' : '0');
993 count -= 1;
994 }
995 if (count)
996 {
997 stream.Printf("%c",bit5 ? '1' : '0');
998 count -= 1;
999 }
1000 if (count)
1001 {
1002 stream.Printf("%c",bit4 ? '1' : '0');
1003 count -= 1;
1004 }
1005 if (count)
1006 {
1007 stream.Printf("%c",bit3 ? '1' : '0');
1008 count -= 1;
1009 }
1010 if (count)
1011 {
1012 stream.Printf("%c",bit2 ? '1' : '0');
1013 count -= 1;
1014 }
1015 if (count)
1016 {
1017 stream.Printf("%c",bit1 ? '1' : '0');
1018 count -= 1;
1019 }
1020 if (count)
1021 {
1022 stream.Printf("%c",bit0 ? '1' : '0');
1023 count -= 1;
1024 }
1025 }
1026 return true;
1027}
1028
1029bool
Enrico Granatadc1df6b2013-03-16 00:50:25 +00001030lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream)
1031{
1032 ProcessSP process_sp = valobj.GetProcessSP();
1033 if (!process_sp)
1034 return false;
1035
1036 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1037
1038 if (!runtime)
1039 return false;
1040
1041 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1042
1043 if (!descriptor.get() || !descriptor->IsValid())
1044 return false;
1045
1046 uint32_t ptr_size = process_sp->GetAddressByteSize();
1047
1048 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1049
1050 if (!valobj_addr)
1051 return false;
1052
1053 uint32_t count = 0;
1054
1055 bool is_type_ok = false; // check to see if this is a CFBinaryHeap we know about
1056 if (descriptor->IsCFType())
1057 {
1058 ConstString type_name(valobj.GetTypeName());
1059 if (type_name == ConstString("__CFBinaryHeap") || type_name == ConstString("const struct __CFBinaryHeap"))
1060 {
1061 if (valobj.IsPointerType())
1062 is_type_ok = true;
1063 }
1064 }
1065
1066 if (is_type_ok == false)
1067 {
1068 StackFrameSP frame_sp(valobj.GetFrameSP());
1069 if (!frame_sp)
1070 return false;
1071 ValueObjectSP count_sp;
1072 StreamString expr;
1073 expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
1074 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
1075 return false;
1076 if (!count_sp)
1077 return false;
1078 count = count_sp->GetValueAsUnsigned(0);
1079 }
1080 else
1081 {
1082 uint32_t offset = 2*ptr_size;
1083 Error error;
1084 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
1085 if (error.Fail())
1086 return false;
1087 }
1088 stream.Printf("@\"%u item%s\"",
1089 count,(count == 1 ? "" : "s"));
1090 return true;
1091}
1092
1093bool
Enrico Granata3818e6a2013-03-16 01:18:00 +00001094lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream)
1095{
1096 ProcessSP process_sp = valobj.GetProcessSP();
1097 if (!process_sp)
1098 return false;
1099
1100 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1101
1102 if (!runtime)
1103 return false;
1104
1105 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1106
1107 if (!descriptor.get() || !descriptor->IsValid())
1108 return false;
1109
1110 uint32_t ptr_size = process_sp->GetAddressByteSize();
1111
1112 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1113
1114 if (!valobj_addr)
1115 return false;
1116
1117 const char* class_name = descriptor->GetClassName().GetCString();
1118
1119 if (!class_name || !*class_name)
1120 return false;
1121
1122 uint64_t count = 0;
1123
1124 do {
1125 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
1126 {
1127 Error error;
1128 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
1129 if (error.Fail())
1130 return false;
1131 // this means the set is empty - count = 0
1132 if ((mode & 1) == 1)
1133 {
1134 count = 0;
1135 break;
1136 }
1137 if ((mode & 2) == 2)
1138 mode = 1; // this means the set only has one range
1139 else
1140 mode = 2; // this means the set has multiple ranges
1141 if (mode == 1)
1142 {
1143 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
1144 if (error.Fail())
1145 return false;
1146 }
1147 else
1148 {
1149 // read a pointer to the data at 2*ptr_size
1150 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
1151 if (error.Fail())
1152 return false;
1153 // read the data at 2*ptr_size from the first location
1154 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
1155 if (error.Fail())
1156 return false;
1157 }
1158 }
1159 else
1160 {
1161 if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
1162 return false;
1163 }
1164 } while (false);
1165 stream.Printf("%llu index%s",
1166 count,
1167 (count == 1 ? "" : "es"));
1168 return true;
1169}
1170
1171bool
Enrico Granataf91e78f2012-09-13 18:27:09 +00001172lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +00001173{
1174 ProcessSP process_sp = valobj.GetProcessSP();
1175 if (!process_sp)
1176 return false;
1177
1178 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1179
1180 if (!runtime)
1181 return false;
1182
1183 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1184
1185 if (!descriptor.get() || !descriptor->IsValid())
1186 return false;
1187
1188 uint32_t ptr_size = process_sp->GetAddressByteSize();
1189
1190 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1191
1192 if (!valobj_addr)
1193 return false;
1194
1195 const char* class_name = descriptor->GetClassName().GetCString();
1196
Enrico Granata7685a562012-09-29 00:47:43 +00001197 if (!class_name || !*class_name)
1198 return false;
1199
Enrico Granatacaaf0102012-09-04 18:48:21 +00001200 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
1201 {
1202 if (descriptor->IsTagged())
1203 {
1204 // we have a call to get info and value bits in the tagged descriptor. but we prefer not to cast and replicate them
1205 int64_t value = (valobj_addr & ~0x0000000000000000FFL) >> 8;
1206 uint64_t i_bits = (valobj_addr & 0xF0) >> 4;
1207
1208 switch (i_bits)
1209 {
1210 case 0:
1211 stream.Printf("(char)%hhd",(char)value);
1212 break;
1213 case 4:
1214 stream.Printf("(short)%hd",(short)value);
1215 break;
1216 case 8:
1217 stream.Printf("(int)%d",(int)value);
1218 break;
1219 case 12:
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001220 stream.Printf("(long)%" PRId64,value);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001221 break;
1222 default:
Enrico Granata3ca24b42012-12-10 19:23:00 +00001223 stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001224 break;
1225 }
1226 return true;
1227 }
1228 else
1229 {
1230 Error error;
1231 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
1232 uint64_t data_location = valobj_addr + 2*ptr_size;
1233 uint64_t value = 0;
1234 if (error.Fail())
1235 return false;
1236 switch (data_type)
1237 {
1238 case 1: // 0B00001
1239 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
1240 if (error.Fail())
1241 return false;
1242 stream.Printf("(char)%hhd",(char)value);
1243 break;
1244 case 2: // 0B0010
1245 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
1246 if (error.Fail())
1247 return false;
1248 stream.Printf("(short)%hd",(short)value);
1249 break;
1250 case 3: // 0B0011
1251 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
1252 if (error.Fail())
1253 return false;
1254 stream.Printf("(int)%d",(int)value);
1255 break;
1256 case 17: // 0B10001
1257 data_location += 8;
1258 case 4: // 0B0100
1259 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
1260 if (error.Fail())
1261 return false;
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001262 stream.Printf("(long)%" PRId64,value);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001263 break;
1264 case 5: // 0B0101
1265 {
1266 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
1267 if (error.Fail())
1268 return false;
1269 float flt_value = *((float*)&flt_as_int);
1270 stream.Printf("(float)%f",flt_value);
1271 break;
1272 }
1273 case 6: // 0B0110
1274 {
1275 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
1276 if (error.Fail())
1277 return false;
1278 double dbl_value = *((double*)&dbl_as_lng);
1279 stream.Printf("(double)%g",dbl_value);
1280 break;
1281 }
1282 default:
1283 stream.Printf("absurd: dt=%d",data_type);
1284 break;
1285 }
1286 return true;
1287 }
1288 }
1289 else
1290 {
Enrico Granataea687532013-02-15 23:38:37 +00001291 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001292 }
1293}
1294
Enrico Granataf3a217e2013-02-21 20:31:18 +00001295static bool
1296ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
1297 lldb::ProcessSP& process_sp,
1298 Stream& dest,
1299 size_t size = 0,
1300 Error* error = NULL,
1301 size_t *data_read = NULL,
1302 char prefix_token = '@',
1303 char quote = '"')
1304{
1305 Error my_error;
1306 size_t my_data_read;
1307 if (!process_sp || location == 0)
1308 return false;
1309
1310 if (size == 0)
1311 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
1312
1313 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
1314
1315 my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error);
1316
1317 if (error)
1318 *error = my_error;
1319 if (data_read)
1320 *data_read = my_data_read;
1321
1322 if (my_error.Fail())
1323 return false;
1324 if (my_data_read)
1325 dest.Printf("%c%c%s%c",prefix_token,quote,(char*)buffer_sp->GetBytes(),quote);
1326
1327 return true;
1328}
1329
Enrico Granatacaaf0102012-09-04 18:48:21 +00001330bool
Enrico Granataf91e78f2012-09-13 18:27:09 +00001331lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
Enrico Granatacaaf0102012-09-04 18:48:21 +00001332{
1333 ProcessSP process_sp = valobj.GetProcessSP();
1334 if (!process_sp)
1335 return false;
1336
1337 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1338
1339 if (!runtime)
1340 return false;
1341
1342 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1343
1344 if (!descriptor.get() || !descriptor->IsValid())
1345 return false;
1346
1347 uint32_t ptr_size = process_sp->GetAddressByteSize();
1348
1349 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1350
1351 if (!valobj_addr)
1352 return false;
1353
1354 const char* class_name = descriptor->GetClassName().GetCString();
1355
Enrico Granata25c9ade2012-09-29 00:45:53 +00001356 if (!class_name || !*class_name)
1357 return false;
1358
Enrico Granatacaaf0102012-09-04 18:48:21 +00001359 uint64_t info_bits_location = valobj_addr + ptr_size;
1360 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
1361 info_bits_location += 3;
1362
Enrico Granataf3a217e2013-02-21 20:31:18 +00001363 Error error;
Enrico Granatacaaf0102012-09-04 18:48:21 +00001364
1365 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
1366 if (error.Fail())
1367 return false;
1368
1369 bool is_mutable = (info_bits & 1) == 1;
1370 bool is_inline = (info_bits & 0x60) == 0;
1371 bool has_explicit_length = (info_bits & (1 | 4)) != 4;
1372 bool is_unicode = (info_bits & 0x10) == 0x10;
1373 bool is_special = strcmp(class_name,"NSPathStore2") == 0;
1374
1375 if (strcmp(class_name,"NSString") &&
1376 strcmp(class_name,"CFStringRef") &&
1377 strcmp(class_name,"CFMutableStringRef") &&
1378 strcmp(class_name,"__NSCFConstantString") &&
1379 strcmp(class_name,"__NSCFString") &&
1380 strcmp(class_name,"NSCFConstantString") &&
1381 strcmp(class_name,"NSCFString") &&
1382 strcmp(class_name,"NSPathStore2"))
1383 {
Enrico Granataf3a217e2013-02-21 20:31:18 +00001384 // not one of us - but tell me class name
1385 stream.Printf("class name = %s",class_name);
1386 return true;
Enrico Granatacaaf0102012-09-04 18:48:21 +00001387 }
1388
1389 if (is_mutable)
1390 {
1391 uint64_t location = 2 * ptr_size + valobj_addr;
1392 location = process_sp->ReadPointerFromMemory(location, error);
1393 if (error.Fail())
1394 return false;
1395 if (has_explicit_length and is_unicode)
Enrico Granatacd8cd612013-01-14 23:53:26 +00001396 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@');
Enrico Granatacaaf0102012-09-04 18:48:21 +00001397 else
Enrico Granataf3a217e2013-02-21 20:31:18 +00001398 return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001399 }
1400 else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
1401 {
1402 uint64_t location = 3 * ptr_size + valobj_addr;
Enrico Granataf3a217e2013-02-21 20:31:18 +00001403 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001404 }
1405 else if (is_unicode)
1406 {
Enrico Granataf3a217e2013-02-21 20:31:18 +00001407 uint64_t location = valobj_addr + 2*ptr_size;
Enrico Granatacaaf0102012-09-04 18:48:21 +00001408 if (is_inline)
1409 {
1410 if (!has_explicit_length)
1411 {
1412 stream.Printf("found new combo");
1413 return true;
1414 }
1415 else
1416 location += ptr_size;
1417 }
1418 else
1419 {
1420 location = process_sp->ReadPointerFromMemory(location, error);
1421 if (error.Fail())
1422 return false;
1423 }
Enrico Granatacd8cd612013-01-14 23:53:26 +00001424 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
Enrico Granatacaaf0102012-09-04 18:48:21 +00001425 }
1426 else if (is_special)
1427 {
1428 uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
Enrico Granatacd8cd612013-01-14 23:53:26 +00001429 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
Enrico Granatacaaf0102012-09-04 18:48:21 +00001430 }
1431 else if (is_inline)
1432 {
Enrico Granataf3a217e2013-02-21 20:31:18 +00001433 uint64_t location = valobj_addr + 2*ptr_size;
Enrico Granatacaaf0102012-09-04 18:48:21 +00001434 if (!has_explicit_length)
1435 location++;
Enrico Granataf3a217e2013-02-21 20:31:18 +00001436 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001437 }
1438 else
1439 {
Enrico Granataf3a217e2013-02-21 20:31:18 +00001440 uint64_t location = valobj_addr + 2*ptr_size;
Enrico Granatacaaf0102012-09-04 18:48:21 +00001441 location = process_sp->ReadPointerFromMemory(location, error);
1442 if (error.Fail())
1443 return false;
Enrico Granataf3a217e2013-02-21 20:31:18 +00001444 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
Enrico Granatacaaf0102012-09-04 18:48:21 +00001445 }
1446
1447 stream.Printf("class name = %s",class_name);
1448 return true;
1449
1450}
1451
Enrico Granata9abbfba2012-10-03 23:53:45 +00001452bool
Enrico Granatadcffc1a2013-02-08 01:55:46 +00001453lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1454{
1455 TargetSP target_sp(valobj.GetTargetSP());
1456 if (!target_sp)
1457 return false;
1458 uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
1459 uint64_t pointee = valobj.GetValueAsUnsigned(0);
1460 if (!pointee)
1461 return false;
1462 pointee += addr_size;
1463 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
1464 ExecutionContext exe_ctx(target_sp,false);
1465 ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type));
1466 if (!child_ptr_sp)
1467 return false;
1468 DataExtractor data;
1469 child_ptr_sp->GetData(data);
1470 ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
1471 child_sp->GetValueAsUnsigned(0);
1472 if (child_sp)
1473 return NSStringSummaryProvider(*child_sp, stream);
1474 return false;
1475}
1476
1477bool
1478lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1479{
1480 return NSAttributedStringSummaryProvider(valobj, stream);
1481}
1482
1483bool
Enrico Granata9abbfba2012-10-03 23:53:45 +00001484lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
1485{
1486 stream.Printf("%s",valobj.GetObjectDescription());
1487 return true;
1488}
1489
Enrico Granatadb054912012-10-29 21:18:03 +00001490bool
Enrico Granata979c4b52013-02-08 19:28:04 +00001491lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
1492{
1493 ProcessSP process_sp = valobj.GetProcessSP();
1494 if (!process_sp)
1495 return false;
1496
1497 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1498
1499 if (!runtime)
1500 return false;
1501
1502 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1503
1504 if (!descriptor.get() || !descriptor->IsValid())
1505 return false;
1506
1507 uint32_t ptr_size = process_sp->GetAddressByteSize();
1508
1509 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1510
1511 if (!valobj_addr)
1512 return false;
1513
1514 const char* class_name = descriptor->GetClassName().GetCString();
1515
1516 if (!class_name || !*class_name)
1517 return false;
1518
1519 if (strcmp(class_name, "NSURL") == 0)
1520 {
1521 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
1522 uint64_t offset_base = offset_text + ptr_size;
1523 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
1524 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
1525 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
Enrico Granata2fd26152013-02-08 23:54:46 +00001526 if (!text)
Enrico Granata979c4b52013-02-08 19:28:04 +00001527 return false;
1528 if (text->GetValueAsUnsigned(0) == 0)
1529 return false;
1530 StreamString summary;
1531 if (!NSStringSummaryProvider(*text, summary))
1532 return false;
Enrico Granata2fd26152013-02-08 23:54:46 +00001533 if (base && base->GetValueAsUnsigned(0))
Enrico Granata979c4b52013-02-08 19:28:04 +00001534 {
1535 if (summary.GetSize() > 0)
1536 summary.GetString().resize(summary.GetSize()-1);
1537 summary.Printf(" -- ");
1538 StreamString base_summary;
Enrico Granata2fd26152013-02-08 23:54:46 +00001539 if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0)
Enrico Granata979c4b52013-02-08 19:28:04 +00001540 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
1541 }
1542 if (summary.GetSize())
1543 {
1544 stream.Printf("%s",summary.GetData());
1545 return true;
1546 }
1547 }
1548 else
1549 {
Enrico Granataea687532013-02-15 23:38:37 +00001550 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
Enrico Granata979c4b52013-02-08 19:28:04 +00001551 }
1552 return false;
1553}
1554
1555bool
Enrico Granatadb054912012-10-29 21:18:03 +00001556lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
1557{
1558 const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(),
1559 valobj.GetClangAST(),
1560 NULL);
1561
1562 ValueObjectSP real_guy_sp = valobj.GetSP();
1563
1564 if (type_info & ClangASTContext::eTypeIsPointer)
1565 {
1566 Error err;
1567 real_guy_sp = valobj.Dereference(err);
1568 if (err.Fail() || !real_guy_sp)
1569 return false;
1570 }
1571 else if (type_info & ClangASTContext::eTypeIsReference)
1572 {
1573 real_guy_sp = valobj.GetChildAtIndex(0, true);
1574 if (!real_guy_sp)
1575 return false;
1576 }
1577 uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
1578 if (value == 0)
1579 {
1580 stream.Printf("NO");
1581 return true;
1582 }
1583 stream.Printf("YES");
1584 return true;
1585}
1586
1587template <bool is_sel_ptr>
1588bool
1589lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
1590{
Enrico Granata1f9df782013-02-15 00:06:04 +00001591 lldb::ValueObjectSP valobj_sp;
Enrico Granatadb054912012-10-29 21:18:03 +00001592
Enrico Granata1f9df782013-02-15 00:06:04 +00001593 if (!valobj.GetClangAST())
Enrico Granatadb054912012-10-29 21:18:03 +00001594 return false;
Enrico Granata1f9df782013-02-15 00:06:04 +00001595 void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr();
1596 if (!char_opaque_type)
1597 return false;
1598 ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type));
1599
Enrico Granatadb054912012-10-29 21:18:03 +00001600 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1601
Enrico Granata1f9df782013-02-15 00:06:04 +00001602 if (is_sel_ptr)
1603 {
1604 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1605 if (data_address == LLDB_INVALID_ADDRESS)
1606 return false;
1607 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
1608 }
1609 else
1610 {
1611 DataExtractor data;
1612 valobj.GetData(data);
1613 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
1614 }
Enrico Granatadb054912012-10-29 21:18:03 +00001615
Enrico Granata1f9df782013-02-15 00:06:04 +00001616 if (!valobj_sp)
1617 return false;
Enrico Granatadb054912012-10-29 21:18:03 +00001618
1619 stream.Printf("%s",valobj_sp->GetSummaryAsCString());
1620 return true;
1621}
1622
Enrico Granatacba09f62013-03-19 00:27:22 +00001623// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1624// this call gives the POSIX equivalent of the Cocoa epoch
1625time_t
1626GetOSXEpoch ()
1627{
1628 static time_t epoch = 0;
1629 if (!epoch)
1630 {
1631 tzset();
1632 tm tm_epoch;
1633 tm_epoch.tm_sec = 0;
1634 tm_epoch.tm_hour = 0;
1635 tm_epoch.tm_min = 0;
1636 tm_epoch.tm_mon = 0;
1637 tm_epoch.tm_mday = 1;
1638 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
1639 tm_epoch.tm_isdst = -1;
1640 tm_epoch.tm_gmtoff = 0;
1641 tm_epoch.tm_zone = NULL;
1642 epoch = timegm(&tm_epoch);
1643 }
1644 return epoch;
1645}
1646
1647bool
1648lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
1649{
1650 ProcessSP process_sp = valobj.GetProcessSP();
1651 if (!process_sp)
1652 return false;
1653
1654 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1655
1656 if (!runtime)
1657 return false;
1658
1659 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1660
1661 if (!descriptor.get() || !descriptor->IsValid())
1662 return false;
1663
1664 uint32_t ptr_size = process_sp->GetAddressByteSize();
1665
1666 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1667
1668 if (!valobj_addr)
1669 return false;
1670
1671 uint64_t date_value_bits = 0;
1672 double date_value = 0.0;
1673
1674 const char* class_name = descriptor->GetClassName().GetCString();
1675
1676 if (!class_name || !*class_name)
1677 return false;
1678
1679 if (strcmp(class_name,"NSDate") == 0 ||
1680 strcmp(class_name,"__NSDate") == 0 ||
1681 strcmp(class_name,"__NSTaggedDate") == 0)
1682 {
1683 if (descriptor->IsTagged())
1684 {
1685 uint64_t info_bits = (valobj_addr & 0xF0ULL) >> 4;
1686 uint64_t value_bits = (valobj_addr & ~0x0000000000000000FFULL) >> 8;
1687 date_value_bits = ((value_bits << 8) | (info_bits << 4));
1688 date_value = *((double*)&date_value_bits);
1689 }
1690 else
1691 {
1692 Error error;
1693 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
1694 date_value = *((double*)&date_value_bits);
1695 if (error.Fail())
1696 return false;
1697 }
1698 }
1699 else if (!strcmp(class_name,"NSCalendarDate"))
1700 {
1701 Error error;
1702 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
1703 date_value = *((double*)&date_value_bits);
1704 if (error.Fail())
1705 return false;
1706 }
1707 else
1708 {
1709 if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
1710 return false;
1711 date_value = *((double*)&date_value_bits);
1712 }
1713 if (date_value == -63114076800)
1714 {
1715 stream.Printf("0001-12-30 00:00:00 +0000");
1716 return true;
1717 }
1718 // this snippet of code assumes that time_t == seconds since Jan-1-1970
1719 // this is generally true and POSIXly happy, but might break if a library
1720 // vendor decides to get creative
1721 time_t epoch = GetOSXEpoch();
1722 epoch = epoch + (time_t)date_value;
1723 tm *tm_date = localtime(&epoch);
1724 if (!tm_date)
1725 return false;
1726 std::string buffer(1024,0);
1727 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
1728 return false;
1729 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
1730 return true;
1731}
1732
1733bool
1734lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream)
1735{
1736 time_t epoch = GetOSXEpoch();
1737 epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0);
1738 tm *tm_date = localtime(&epoch);
1739 if (!tm_date)
1740 return false;
1741 std::string buffer(1024,0);
1742 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
1743 return false;
1744 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
1745 return true;
1746}
1747
Greg Clayton36da2aa2013-01-25 18:06:21 +00001748size_t
Enrico Granataea687532013-02-15 23:38:37 +00001749lldb_private::formatters::ExtractIndexFromString (const char* item_name)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001750{
1751 if (!item_name || !*item_name)
1752 return UINT32_MAX;
1753 if (*item_name != '[')
1754 return UINT32_MAX;
1755 item_name++;
Enrico Granataea687532013-02-15 23:38:37 +00001756 char* endptr = NULL;
1757 unsigned long int idx = ::strtoul(item_name, &endptr, 0);
1758 if (idx == 0 && endptr == item_name)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001759 return UINT32_MAX;
Enrico Granataea687532013-02-15 23:38:37 +00001760 if (idx == ULONG_MAX)
Enrico Granataf91e78f2012-09-13 18:27:09 +00001761 return UINT32_MAX;
1762 return idx;
1763}
1764
Enrico Granata32d7ee32013-02-21 19:57:10 +00001765lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
1766 ConstString item_name) :
Enrico Granata689696c2013-02-04 22:54:42 +00001767SyntheticChildrenFrontEnd(*valobj_sp.get()),
1768m_exe_ctx_ref(),
Enrico Granata32d7ee32013-02-21 19:57:10 +00001769m_item_name(item_name),
1770m_item_sp()
Enrico Granata689696c2013-02-04 22:54:42 +00001771{
1772 if (valobj_sp)
1773 Update();
Enrico Granata689696c2013-02-04 22:54:42 +00001774}
1775
Enrico Granata689696c2013-02-04 22:54:42 +00001776bool
Enrico Granata32d7ee32013-02-21 19:57:10 +00001777lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
Enrico Granata689696c2013-02-04 22:54:42 +00001778{
1779 ValueObjectSP valobj_sp = m_backend.GetSP();
1780 if (!valobj_sp)
1781 return false;
Enrico Granata32d7ee32013-02-21 19:57:10 +00001782
Enrico Granata689696c2013-02-04 22:54:42 +00001783 if (!valobj_sp)
1784 return false;
Enrico Granata32d7ee32013-02-21 19:57:10 +00001785
1786 ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
1787 if (!item_ptr)
1788 return false;
1789 if (item_ptr->GetValueAsUnsigned(0) == 0)
1790 return false;
1791 Error err;
Enrico Granata689696c2013-02-04 22:54:42 +00001792 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
Enrico Granata32d7ee32013-02-21 19:57:10 +00001793 m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType())));
1794 if (err.Fail())
1795 m_item_sp.reset();
1796 return (m_item_sp.get() != NULL);
1797}
Enrico Granata689696c2013-02-04 22:54:42 +00001798
Enrico Granata32d7ee32013-02-21 19:57:10 +00001799size_t
1800lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
1801{
1802 return 1;
1803}
Enrico Granata689696c2013-02-04 22:54:42 +00001804
Enrico Granata32d7ee32013-02-21 19:57:10 +00001805lldb::ValueObjectSP
1806lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1807{
1808 if (idx == 0)
1809 return m_item_sp;
1810 return lldb::ValueObjectSP();
Enrico Granata689696c2013-02-04 22:54:42 +00001811}
1812
1813bool
Enrico Granata32d7ee32013-02-21 19:57:10 +00001814lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
Enrico Granata689696c2013-02-04 22:54:42 +00001815{
1816 return true;
1817}
1818
1819size_t
Enrico Granata32d7ee32013-02-21 19:57:10 +00001820lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
Enrico Granata689696c2013-02-04 22:54:42 +00001821{
Enrico Granata32d7ee32013-02-21 19:57:10 +00001822 if (name == ConstString("item"))
1823 return 0;
1824 return UINT32_MAX;
Enrico Granata689696c2013-02-04 22:54:42 +00001825}
1826
Enrico Granata32d7ee32013-02-21 19:57:10 +00001827lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
Enrico Granata689696c2013-02-04 22:54:42 +00001828{
Enrico Granata689696c2013-02-04 22:54:42 +00001829}
1830
Enrico Granatacaaf0102012-09-04 18:48:21 +00001831template bool
Enrico Granataf91e78f2012-09-13 18:27:09 +00001832lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
1833
1834template bool
1835lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
Enrico Granatadb054912012-10-29 21:18:03 +00001836
1837template bool
1838lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
1839
1840template bool
1841lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;