CF.cpp revision cc5d27417b9f958d596a438290a9adb17674b487
1//===-- CF.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
10#include "lldb/DataFormatters/CXXFormatterFunctions.h"
11
12#include "lldb/Core/DataBufferHeap.h"
13#include "lldb/Core/Error.h"
14#include "lldb/Core/Stream.h"
15#include "lldb/Core/ValueObject.h"
16#include "lldb/Core/ValueObjectConstResult.h"
17#include "lldb/Host/Endian.h"
18#include "lldb/Symbol/ClangASTContext.h"
19#include "lldb/Target/ObjCLanguageRuntime.h"
20#include "lldb/Target/Target.h"
21
22using namespace lldb;
23using namespace lldb_private;
24using namespace lldb_private::formatters;
25
26bool
27lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream)
28{
29    time_t epoch = GetOSXEpoch();
30    epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0);
31    tm *tm_date = localtime(&epoch);
32    if (!tm_date)
33        return false;
34    std::string buffer(1024,0);
35    if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
36        return false;
37    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());
38    return true;
39}
40
41bool
42lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream)
43{
44    ProcessSP process_sp = valobj.GetProcessSP();
45    if (!process_sp)
46        return false;
47
48    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
49
50    if (!runtime)
51        return false;
52
53    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
54
55    if (!descriptor.get() || !descriptor->IsValid())
56        return false;
57
58    uint32_t ptr_size = process_sp->GetAddressByteSize();
59
60    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
61
62    if (!valobj_addr)
63        return false;
64
65    uint32_t count = 0;
66
67    bool is_type_ok = false; // check to see if this is a CFBag we know about
68    if (descriptor->IsCFType())
69    {
70        ConstString type_name(valobj.GetTypeName());
71        if (type_name == ConstString("__CFBag") || type_name == ConstString("const struct __CFBag"))
72        {
73            if (valobj.IsPointerType())
74                is_type_ok = true;
75        }
76    }
77
78    if (is_type_ok == false)
79    {
80        StackFrameSP frame_sp(valobj.GetFrameSP());
81        if (!frame_sp)
82            return false;
83        ValueObjectSP count_sp;
84        StreamString expr;
85        expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
86        if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
87            return false;
88        if (!count_sp)
89            return false;
90        count = count_sp->GetValueAsUnsigned(0);
91    }
92    else
93    {
94        uint32_t offset = 2*ptr_size+4 + valobj_addr;
95        Error error;
96        count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
97        if (error.Fail())
98            return false;
99    }
100    stream.Printf("@\"%u value%s\"",
101                  count,(count == 1 ? "" : "s"));
102    return true;
103}
104
105bool
106lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream)
107{
108    ProcessSP process_sp = valobj.GetProcessSP();
109    if (!process_sp)
110        return false;
111
112    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
113
114    if (!runtime)
115        return false;
116
117    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
118
119    if (!descriptor.get() || !descriptor->IsValid())
120        return false;
121
122    uint32_t ptr_size = process_sp->GetAddressByteSize();
123
124    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
125
126    if (!valobj_addr)
127        return false;
128
129    uint32_t count = 0;
130
131    bool is_type_ok = false; // check to see if this is a CFBag we know about
132    if (descriptor->IsCFType())
133    {
134        ConstString type_name(valobj.GetTypeName());
135        if (type_name == ConstString("__CFMutableBitVector") || type_name == ConstString("__CFBitVector") || type_name == ConstString("CFMutableBitVectorRef") || type_name == ConstString("CFBitVectorRef"))
136        {
137            if (valobj.IsPointerType())
138                is_type_ok = true;
139        }
140    }
141
142    if (is_type_ok == false)
143        return false;
144
145    Error error;
146    count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
147    if (error.Fail())
148        return false;
149    uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
150    addr_t data_ptr = process_sp->ReadPointerFromMemory(valobj_addr+2*ptr_size+2*ptr_size, error);
151    if (error.Fail())
152        return false;
153    // make sure we do not try to read huge amounts of data
154    if (num_bytes > 1024)
155        num_bytes = 1024;
156    DataBufferSP buffer_sp(new DataBufferHeap(num_bytes,0));
157    num_bytes = process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
158    if (error.Fail())
159        return false;
160    for (int byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
161    {
162        uint8_t byte = buffer_sp->GetBytes()[byte_idx];
163        bool bit0 = (byte & 1) == 1;
164        bool bit1 = (byte & 2) == 2;
165        bool bit2 = (byte & 4) == 4;
166        bool bit3 = (byte & 8) == 8;
167        bool bit4 = (byte & 16) == 16;
168        bool bit5 = (byte & 32) == 32;
169        bool bit6 = (byte & 64) == 64;
170        bool bit7 = (byte & 128) == 128;
171        stream.Printf("%c%c%c%c %c%c%c%c ",
172                      (bit7 ? '1' : '0'),
173                      (bit6 ? '1' : '0'),
174                      (bit5 ? '1' : '0'),
175                      (bit4 ? '1' : '0'),
176                      (bit3 ? '1' : '0'),
177                      (bit2 ? '1' : '0'),
178                      (bit1 ? '1' : '0'),
179                      (bit0 ? '1' : '0'));
180        count -= 8;
181    }
182    {
183        // print the last byte ensuring we do not print spurious bits
184        uint8_t byte = buffer_sp->GetBytes()[num_bytes-1];
185        bool bit0 = (byte & 1) == 1;
186        bool bit1 = (byte & 2) == 2;
187        bool bit2 = (byte & 4) == 4;
188        bool bit3 = (byte & 8) == 8;
189        bool bit4 = (byte & 16) == 16;
190        bool bit5 = (byte & 32) == 32;
191        bool bit6 = (byte & 64) == 64;
192        bool bit7 = (byte & 128) == 128;
193        if (count)
194        {
195            stream.Printf("%c",bit7 ? '1' : '0');
196            count -= 1;
197        }
198        if (count)
199        {
200            stream.Printf("%c",bit6 ? '1' : '0');
201            count -= 1;
202        }
203        if (count)
204        {
205            stream.Printf("%c",bit5 ? '1' : '0');
206            count -= 1;
207        }
208        if (count)
209        {
210            stream.Printf("%c",bit4 ? '1' : '0');
211            count -= 1;
212        }
213        if (count)
214        {
215            stream.Printf("%c",bit3 ? '1' : '0');
216            count -= 1;
217        }
218        if (count)
219        {
220            stream.Printf("%c",bit2 ? '1' : '0');
221            count -= 1;
222        }
223        if (count)
224        {
225            stream.Printf("%c",bit1 ? '1' : '0');
226            count -= 1;
227        }
228        if (count)
229        {
230            stream.Printf("%c",bit0 ? '1' : '0');
231            count -= 1;
232        }
233    }
234    return true;
235}
236
237bool
238lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream)
239{
240    ProcessSP process_sp = valobj.GetProcessSP();
241    if (!process_sp)
242        return false;
243
244    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
245
246    if (!runtime)
247        return false;
248
249    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
250
251    if (!descriptor.get() || !descriptor->IsValid())
252        return false;
253
254    uint32_t ptr_size = process_sp->GetAddressByteSize();
255
256    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
257
258    if (!valobj_addr)
259        return false;
260
261    uint32_t count = 0;
262
263    bool is_type_ok = false; // check to see if this is a CFBinaryHeap we know about
264    if (descriptor->IsCFType())
265    {
266        ConstString type_name(valobj.GetTypeName());
267        if (type_name == ConstString("__CFBinaryHeap") || type_name == ConstString("const struct __CFBinaryHeap"))
268        {
269            if (valobj.IsPointerType())
270                is_type_ok = true;
271        }
272    }
273
274    if (is_type_ok == false)
275    {
276        StackFrameSP frame_sp(valobj.GetFrameSP());
277        if (!frame_sp)
278            return false;
279        ValueObjectSP count_sp;
280        StreamString expr;
281        expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
282        if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
283            return false;
284        if (!count_sp)
285            return false;
286        count = count_sp->GetValueAsUnsigned(0);
287    }
288    else
289    {
290        uint32_t offset = 2*ptr_size;
291        Error error;
292        count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
293        if (error.Fail())
294            return false;
295    }
296    stream.Printf("@\"%u item%s\"",
297                  count,(count == 1 ? "" : "s"));
298    return true;
299}
300