1//===-- ValueObjectChild.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/Core/ValueObjectChild.h"
11
12#include "lldb/Core/Module.h"
13#include "lldb/Core/ValueObjectList.h"
14
15#include "lldb/Symbol/ClangASTType.h"
16#include "lldb/Symbol/ObjectFile.h"
17#include "lldb/Symbol/SymbolContext.h"
18#include "lldb/Symbol/Type.h"
19#include "lldb/Symbol/Variable.h"
20
21#include "lldb/Target/ExecutionContext.h"
22#include "lldb/Target/Process.h"
23#include "lldb/Target/Target.h"
24
25using namespace lldb_private;
26
27ValueObjectChild::ValueObjectChild
28(
29    ValueObject &parent,
30    const ClangASTType &clang_type,
31    const ConstString &name,
32    uint64_t byte_size,
33    int32_t byte_offset,
34    uint32_t bitfield_bit_size,
35    uint32_t bitfield_bit_offset,
36    bool is_base_class,
37    bool is_deref_of_parent,
38    AddressType child_ptr_or_ref_addr_type
39) :
40    ValueObject (parent),
41    m_clang_type (clang_type),
42    m_byte_size (byte_size),
43    m_byte_offset (byte_offset),
44    m_bitfield_bit_size (bitfield_bit_size),
45    m_bitfield_bit_offset (bitfield_bit_offset),
46    m_is_base_class (is_base_class),
47    m_is_deref_of_parent (is_deref_of_parent)
48{
49    m_name = name;
50    SetAddressTypeOfChildren(child_ptr_or_ref_addr_type);
51}
52
53ValueObjectChild::~ValueObjectChild()
54{
55}
56
57lldb::ValueType
58ValueObjectChild::GetValueType() const
59{
60    return m_parent->GetValueType();
61}
62
63size_t
64ValueObjectChild::CalculateNumChildren()
65{
66    return GetClangType().GetNumChildren (true);
67}
68
69ConstString
70ValueObjectChild::GetTypeName()
71{
72    if (m_type_name.IsEmpty())
73    {
74        m_type_name = GetClangType().GetConstTypeName ();
75        if (m_type_name)
76        {
77            if (m_bitfield_bit_size > 0)
78            {
79                const char *clang_type_name = m_type_name.AsCString();
80                if (clang_type_name)
81                {
82                    std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
83                    ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
84                    m_type_name.SetCString(&bitfield_type_name.front());
85                }
86            }
87        }
88    }
89    return m_type_name;
90}
91
92ConstString
93ValueObjectChild::GetQualifiedTypeName()
94{
95    ConstString qualified_name = GetClangType().GetConstTypeName();
96    if (qualified_name)
97    {
98        if (m_bitfield_bit_size > 0)
99        {
100            const char *clang_type_name = qualified_name.AsCString();
101            if (clang_type_name)
102            {
103                std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
104                ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
105                qualified_name.SetCString(&bitfield_type_name.front());
106            }
107        }
108    }
109    return qualified_name;
110}
111
112bool
113ValueObjectChild::UpdateValue ()
114{
115    m_error.Clear();
116    SetValueIsValid (false);
117    ValueObject* parent = m_parent;
118    if (parent)
119    {
120        if (parent->UpdateValueIfNeeded(false))
121        {
122            m_value.SetClangType(GetClangType());
123
124            // Copy the parent scalar value and the scalar value type
125            m_value.GetScalar() = parent->GetValue().GetScalar();
126            Value::ValueType value_type = parent->GetValue().GetValueType();
127            m_value.SetValueType (value_type);
128
129            if (parent->GetClangType().IsPointerOrReferenceType ())
130            {
131                lldb::addr_t addr = parent->GetPointerValue ();
132                m_value.GetScalar() = addr;
133
134                if (addr == LLDB_INVALID_ADDRESS)
135                {
136                    m_error.SetErrorString ("parent address is invalid.");
137                }
138                else if (addr == 0)
139                {
140                    m_error.SetErrorString ("parent is NULL");
141                }
142                else
143                {
144                    m_value.GetScalar() += m_byte_offset;
145                    AddressType addr_type = parent->GetAddressTypeOfChildren();
146
147                    switch (addr_type)
148                    {
149                        case eAddressTypeFile:
150                            {
151                                lldb::ProcessSP process_sp (GetProcessSP());
152                                if (process_sp && process_sp->IsAlive() == true)
153                                    m_value.SetValueType (Value::eValueTypeLoadAddress);
154                                else
155                                    m_value.SetValueType(Value::eValueTypeFileAddress);
156                            }
157                            break;
158                        case eAddressTypeLoad:
159                            m_value.SetValueType (Value::eValueTypeLoadAddress);
160                            break;
161                        case eAddressTypeHost:
162                            m_value.SetValueType(Value::eValueTypeHostAddress);
163                            break;
164                        case eAddressTypeInvalid:
165                            // TODO: does this make sense?
166                            m_value.SetValueType(Value::eValueTypeScalar);
167                            break;
168                    }
169                }
170            }
171            else
172            {
173                switch (value_type)
174                {
175                case Value::eValueTypeLoadAddress:
176                case Value::eValueTypeFileAddress:
177                case Value::eValueTypeHostAddress:
178                    {
179                        lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
180                        if (addr == LLDB_INVALID_ADDRESS)
181                        {
182                            m_error.SetErrorString ("parent address is invalid.");
183                        }
184                        else if (addr == 0)
185                        {
186                            m_error.SetErrorString ("parent is NULL");
187                        }
188                        else
189                        {
190                            // Set this object's scalar value to the address of its
191                            // value by adding its byte offset to the parent address
192                            m_value.GetScalar() += GetByteOffset();
193                        }
194                    }
195                    break;
196
197                case Value::eValueTypeScalar:
198                    // TODO: What if this is a register value? Do we try and
199                    // extract the child value from within the parent data?
200                    // Probably...
201                default:
202                    m_error.SetErrorString ("parent has invalid value.");
203                    break;
204                }
205            }
206
207            if (m_error.Success())
208            {
209                ExecutionContext exe_ctx (GetExecutionContextRef().Lock());
210                m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
211            }
212        }
213        else
214        {
215            m_error.SetErrorStringWithFormat("parent failed to evaluate: %s", parent->GetError().AsCString());
216        }
217    }
218    else
219    {
220        m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject.");
221    }
222
223    return m_error.Success();
224}
225
226
227bool
228ValueObjectChild::IsInScope ()
229{
230    ValueObject* root(GetRoot());
231    if (root)
232        return root->IsInScope ();
233    return false;
234}
235