From 6fd87d5d33c677badffcab70b60e8dcc169de07e Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Thu, 4 Aug 2011 01:41:02 +0000 Subject: [PATCH] APIs to GetValueAsSigned/Unsigned() in SBValue now also accept an SBError parameter to give more info about any problem The synthetic children providers now use the new (safer) APIs to get the values of objects As a side effect, fixed an issue in ValueObject where ResolveValue() was not always updating the value before reading it llvm-svn: 136861 --- lldb/examples/synthetic/CFString.py | 8 +-- .../synthetic/StdListSynthProvider.py | 59 +++++++++++-------- .../examples/synthetic/StdMapSynthProvider.py | 4 +- .../synthetic/StdVectorSynthProvider.py | 46 ++++++++++++--- lldb/include/lldb/API/SBValue.h | 6 ++ lldb/scripts/Python/interface/SBValue.i | 8 ++- lldb/source/API/SBValue.cpp | 42 +++++++++++++ lldb/source/Core/ValueObject.cpp | 17 ++++-- .../data-formatter-objc/CFString.py | 8 +-- .../StdListSynthProvider.py | 8 +-- .../StdMapSynthProvider.py | 4 +- .../StdVectorSynthProvider.py | 6 +- 12 files changed, 156 insertions(+), 60 deletions(-) diff --git a/lldb/examples/synthetic/CFString.py b/lldb/examples/synthetic/CFString.py index 7d3a43ae98e8..ed1bd3143468 100644 --- a/lldb/examples/synthetic/CFString.py +++ b/lldb/examples/synthetic/CFString.py @@ -45,7 +45,7 @@ class CFStringSynthProvider: # for 32bit targets, use safe ObjC code return self.handle_unicode_string_safe() offset = 12 - pointer = int(self.valobj.GetValue(), 0) + offset + pointer = self.valobj.GetValueAsUnsigned(0) + offset pystr = self.read_unicode(pointer) return self.valobj.CreateValueFromExpression("content", "(char*)\"" + pystr.encode('utf-8') + "\"") @@ -60,7 +60,7 @@ class CFStringSynthProvider: def handle_unicode_string(self): # step 1: find offset if self.inline: - pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + pointer = self.valobj.GetValueAsUnsigned(0) + self.size_of_cfruntime_base(); if self.explicit == False: # untested, use the safe code path return self.handle_unicode_string_safe(); @@ -76,11 +76,11 @@ class CFStringSynthProvider: # for an inline string) pointer = pointer + 8; else: - pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + pointer = self.valobj.GetValueAsUnsigned(0) + self.size_of_cfruntime_base(); # read 8 bytes here and make an address out of them vopointer = self.valobj.CreateChildAtOffset("dummy", pointer,self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); - pointer = int(vopointer.GetValue(), 0) + pointer = vopointer.GetValueAsUnsigned(0) # step 2: read Unicode data at pointer pystr = self.read_unicode(pointer) # step 3: return it diff --git a/lldb/examples/synthetic/StdListSynthProvider.py b/lldb/examples/synthetic/StdListSynthProvider.py index 0f6ca4d5dd6d..1cfe8c24147a 100644 --- a/lldb/examples/synthetic/StdListSynthProvider.py +++ b/lldb/examples/synthetic/StdListSynthProvider.py @@ -1,61 +1,68 @@ import re class StdListSynthProvider: + def __init__(self, valobj, dict): - self.valobj = valobj; + self.valobj = valobj self.update() + def num_children(self): - next_val = int(self.Mnext.GetValue(),0) - prev_val = int(self.Mprev.GetValue(),0) - if next_val == 0: - return 0; - if next_val == self.Mnode_address: - return 0; + next_val = self.next.GetValueAsUnsigned(0) + prev_val = self.prev.GetValueAsUnsigned(0) + # After a std::list has been initialized, both next and prev will be non-NULL + if next_val == 0 or prev_val == 0: + return 0 + if next_val == self.node_address: + return 0 if next_val == prev_val: - return 1; + return 1 size = 2 - current = self.Mnext - while int(current.GetChildMemberWithName('_M_next').GetValue(),0) != self.Mnode_address: - size = size + 1; + current = self.next + while current.GetChildMemberWithName('_M_next').GetValueAsUnsigned(0) != self.node_address: + size = size + 1 current = current.GetChildMemberWithName('_M_next') return (size - 1) + def get_child_index(self,name): if name == "len": - return self.num_children(); + return self.num_children() else: return int(name.lstrip('[').rstrip(']')) + def get_child_at_index(self,index): if index == self.num_children(): return self.valobj.CreateValueFromExpression("len",str(self.num_children())) else: offset = index - current = self.Mnext; + current = self.next while offset > 0: - current = current.GetChildMemberWithName('_M_next'); - offset = offset - 1; + current = current.GetChildMemberWithName('_M_next') + offset = offset - 1 return current.CreateChildAtOffset('['+str(index)+']',2*current.GetType().GetByteSize(),self.data_type) + def extract_type_name(self,name): self.type_name = name[16:] index = 2 count_of_template = 1 while index < len(self.type_name): if self.type_name[index] == '<': - count_of_template = count_of_template + 1; + count_of_template = count_of_template + 1 elif self.type_name[index] == '>': - count_of_template = count_of_template - 1; + count_of_template = count_of_template - 1 elif self.type_name[index] == ',' and count_of_template == 1: self.type_name = self.type_name[:index] break - index = index + 1; + index = index + 1 self.type_name_nospaces = self.type_name.replace(", ", ",") + def update(self): - self.Mimpl = self.valobj.GetChildMemberWithName('_M_impl') - self.Mnode = self.Mimpl.GetChildMemberWithName('_M_node') - self.extract_type_name(self.Mimpl.GetType().GetName()) - self.Mnode_address = int(self.valobj.AddressOf().GetValue(), 0) - self.Mnext = self.Mnode.GetChildMemberWithName('_M_next') - self.Mprev = self.Mnode.GetChildMemberWithName('_M_prev') - self.data_type = self.Mnode.GetTarget().FindFirstType(self.type_name) + impl = self.valobj.GetChildMemberWithName('_M_impl') + node = impl.GetChildMemberWithName('_M_node') + self.extract_type_name(impl.GetType().GetName()) + self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) + self.next = node.GetChildMemberWithName('_M_next') + self.prev = node.GetChildMemberWithName('_M_prev') + self.data_type = node.GetTarget().FindFirstType(self.type_name) # tries to fight against a difference in formatting type names between gcc and clang if self.data_type.IsValid() == False: - self.data_type = self.Mnode.GetTarget().FindFirstType(self.type_name_nospaces) + self.data_type = node.GetTarget().FindFirstType(self.type_name_nospaces) self.data_size = self.data_type.GetByteSize() diff --git a/lldb/examples/synthetic/StdMapSynthProvider.py b/lldb/examples/synthetic/StdMapSynthProvider.py index 0665889896ea..bb109331e228 100644 --- a/lldb/examples/synthetic/StdMapSynthProvider.py +++ b/lldb/examples/synthetic/StdMapSynthProvider.py @@ -58,7 +58,7 @@ class StdMapSynthProvider: root_ptr_val = self.node_ptr_value(self.Mroot) if root_ptr_val == 0: return 0; - return int(self.Mimpl.GetChildMemberWithName('_M_node_count').GetValue(), 0); + return self.Mimpl.GetChildMemberWithName('_M_node_count').GetValueAsUnsigned(0) def get_child_index(self,name): if name == "len": return self.num_children(); @@ -77,7 +77,7 @@ class StdMapSynthProvider: return current.CreateChildAtOffset('['+str(index)+']',self.skip_size,self.data_type) # utility functions def node_ptr_value(self,node): - return int(node.GetValue(),0); + return node.GetValueAsUnsigned(0) def right(self,node): return node.GetChildMemberWithName("_M_right"); def left(self,node): diff --git a/lldb/examples/synthetic/StdVectorSynthProvider.py b/lldb/examples/synthetic/StdVectorSynthProvider.py index 91e634a718af..dc226902d1eb 100644 --- a/lldb/examples/synthetic/StdVectorSynthProvider.py +++ b/lldb/examples/synthetic/StdVectorSynthProvider.py @@ -1,25 +1,55 @@ class StdVectorSynthProvider: + def __init__(self, valobj, dict): self.valobj = valobj; self.update() + def num_children(self): - start_val = int(self.Mstart.GetValue(),0) - finish_val = int(self.Mfinish.GetValue(),0) - return (finish_val-start_val)/self.data_size + start_val = self.start.GetValueAsUnsigned(0) + finish_val = self.finish.GetValueAsUnsigned(0) + end_val = self.end.GetValueAsUnsigned(0) + # Before a vector has been constructed, it will contain bad values + # so we really need to be careful about the length we return since + # unitialized data can cause us to return a huge number. We need + # to also check for any of the start, finish or end of storage values + # being zero (NULL). If any are, then this vector has not been + # initialized yet and we should return zero + + # Make sure nothing is NULL + if start_val == 0 or finish_val == 0 or end_val == 0: + return 0 + # Make sure start is less than finish + if start_val >= finish_val: + return 0 + # Make sure finish is less than or equal to end of storage + if finish_val > end_val: + return 0 + + # We might still get things wrong, so cap things at 256 items for now + # TODO: read a target "settings set" variable for this to allow it to + # be customized + num_children = (finish_val-start_val)/self.data_size + if num_children > 256: + return 256 + return num_children + def get_child_index(self,name): if name == "len": return self.num_children(); else: return int(name.lstrip('[').rstrip(']')) + def get_child_at_index(self,index): if index == self.num_children(): return self.valobj.CreateValueFromExpression("len",str(self.num_children())) else: offset = index * self.data_size - return self.Mstart.CreateChildAtOffset('['+str(index)+']',offset,self.data_type) + return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type) + def update(self): - self.Mimpl = self.valobj.GetChildMemberWithName('_M_impl') - self.Mstart = self.Mimpl.GetChildMemberWithName('_M_start') - self.Mfinish = self.Mimpl.GetChildMemberWithName('_M_finish') - self.data_type = self.Mstart.GetType().GetPointeeType() + impl = self.valobj.GetChildMemberWithName('_M_impl') + self.start = impl.GetChildMemberWithName('_M_start') + self.finish = impl.GetChildMemberWithName('_M_finish') + self.end = impl.GetChildMemberWithName('_M_end_of_storage') + self.data_type = self.start.GetType().GetPointeeType() self.data_size = self.data_type.GetByteSize() diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 5bae9a48087c..4851e43b418c 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -71,6 +71,12 @@ public: const char * GetValue (); + int64_t + GetValueAsSigned(SBError& error, int64_t fail_value=0); + + uint64_t + GetValueAsUnsigned(SBError& error, uint64_t fail_value=0); + int64_t GetValueAsSigned(int64_t fail_value=0); diff --git a/lldb/scripts/Python/interface/SBValue.i b/lldb/scripts/Python/interface/SBValue.i index 22186e1b8a3a..d73e6012c62c 100644 --- a/lldb/scripts/Python/interface/SBValue.i +++ b/lldb/scripts/Python/interface/SBValue.i @@ -95,8 +95,14 @@ public: GetValue (); int64_t - GetValueAsSigned(int64_t fail_value=0); + GetValueAsSigned(SBError& error, int64_t fail_value=0); + uint64_t + GetValueAsUnsigned(SBError& error, uint64_t fail_value=0); + + int64_t + GetValueAsSigned(int64_t fail_value=0); + uint64_t GetValueAsUnsigned(uint64_t fail_value=0); diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index d874cc2fabce..820121132ee7 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -618,6 +618,48 @@ SBValue::GetValueForExpressionPath(const char* expr_path) return sb_value; } +int64_t +SBValue::GetValueAsSigned(SBError& error, int64_t fail_value) +{ + if (m_opaque_sp) + { + if (m_opaque_sp->GetUpdatePoint().GetTargetSP()) + { + Mutex::Locker api_locker (m_opaque_sp->GetUpdatePoint().GetTargetSP()->GetAPIMutex()); + Scalar scalar; + if (m_opaque_sp->ResolveValue (scalar)) + return scalar.GetRawBits64(fail_value); + else + error.SetErrorString("could not get value"); + } + else + error.SetErrorString("could not get target"); + } + error.SetErrorString("invalid SBValue"); + return fail_value; +} + +uint64_t +SBValue::GetValueAsUnsigned(SBError& error, uint64_t fail_value) +{ + if (m_opaque_sp) + { + if (m_opaque_sp->GetUpdatePoint().GetTargetSP()) + { + Mutex::Locker api_locker (m_opaque_sp->GetUpdatePoint().GetTargetSP()->GetAPIMutex()); + Scalar scalar; + if (m_opaque_sp->ResolveValue (scalar)) + return scalar.GetRawBits64(fail_value); + else + error.SetErrorString("could not get value"); + } + else + error.SetErrorString("could not get target"); + } + error.SetErrorString("invalid SBValue"); + return fail_value; +} + int64_t SBValue::GetValueAsSigned(int64_t fail_value) { diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index c9310753d965..fce00f6d4f39 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -331,12 +331,17 @@ ValueObject::GetValue() const bool ValueObject::ResolveValue (Scalar &scalar) { - ExecutionContext exe_ctx; - ExecutionContextScope *exe_scope = GetExecutionContextScope(); - if (exe_scope) - exe_scope->CalculateExecutionContext(exe_ctx); - scalar = m_value.ResolveValue(&exe_ctx, GetClangAST ()); - return scalar.IsValid(); + if (UpdateValueIfNeeded(false)) // make sure that you are up to date before returning anything + { + ExecutionContext exe_ctx; + ExecutionContextScope *exe_scope = GetExecutionContextScope(); + if (exe_scope) + exe_scope->CalculateExecutionContext(exe_ctx); + scalar = m_value.ResolveValue(&exe_ctx, GetClangAST ()); + return scalar.IsValid(); + } + else + return false; } bool diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/CFString.py b/lldb/test/functionalities/data-formatter/data-formatter-objc/CFString.py index 7d3a43ae98e8..ed1bd3143468 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-objc/CFString.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/CFString.py @@ -45,7 +45,7 @@ class CFStringSynthProvider: # for 32bit targets, use safe ObjC code return self.handle_unicode_string_safe() offset = 12 - pointer = int(self.valobj.GetValue(), 0) + offset + pointer = self.valobj.GetValueAsUnsigned(0) + offset pystr = self.read_unicode(pointer) return self.valobj.CreateValueFromExpression("content", "(char*)\"" + pystr.encode('utf-8') + "\"") @@ -60,7 +60,7 @@ class CFStringSynthProvider: def handle_unicode_string(self): # step 1: find offset if self.inline: - pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + pointer = self.valobj.GetValueAsUnsigned(0) + self.size_of_cfruntime_base(); if self.explicit == False: # untested, use the safe code path return self.handle_unicode_string_safe(); @@ -76,11 +76,11 @@ class CFStringSynthProvider: # for an inline string) pointer = pointer + 8; else: - pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + pointer = self.valobj.GetValueAsUnsigned(0) + self.size_of_cfruntime_base(); # read 8 bytes here and make an address out of them vopointer = self.valobj.CreateChildAtOffset("dummy", pointer,self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); - pointer = int(vopointer.GetValue(), 0) + pointer = vopointer.GetValueAsUnsigned(0) # step 2: read Unicode data at pointer pystr = self.read_unicode(pointer) # step 3: return it diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py index c6ccc1814cf2..1cfe8c24147a 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py @@ -6,8 +6,8 @@ class StdListSynthProvider: self.update() def num_children(self): - next_val = int(self.next.GetValue(),0) - prev_val = int(self.prev.GetValue(),0) + next_val = self.next.GetValueAsUnsigned(0) + prev_val = self.prev.GetValueAsUnsigned(0) # After a std::list has been initialized, both next and prev will be non-NULL if next_val == 0 or prev_val == 0: return 0 @@ -17,7 +17,7 @@ class StdListSynthProvider: return 1 size = 2 current = self.next - while int(current.GetChildMemberWithName('_M_next').GetValue(),0) != self.node_address: + while current.GetChildMemberWithName('_M_next').GetValueAsUnsigned(0) != self.node_address: size = size + 1 current = current.GetChildMemberWithName('_M_next') return (size - 1) @@ -58,7 +58,7 @@ class StdListSynthProvider: impl = self.valobj.GetChildMemberWithName('_M_impl') node = impl.GetChildMemberWithName('_M_node') self.extract_type_name(impl.GetType().GetName()) - self.node_address = int(self.valobj.AddressOf().GetValue(), 0) + self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) self.next = node.GetChildMemberWithName('_M_next') self.prev = node.GetChildMemberWithName('_M_prev') self.data_type = node.GetTarget().FindFirstType(self.type_name) diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py index 0665889896ea..bb109331e228 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py @@ -58,7 +58,7 @@ class StdMapSynthProvider: root_ptr_val = self.node_ptr_value(self.Mroot) if root_ptr_val == 0: return 0; - return int(self.Mimpl.GetChildMemberWithName('_M_node_count').GetValue(), 0); + return self.Mimpl.GetChildMemberWithName('_M_node_count').GetValueAsUnsigned(0) def get_child_index(self,name): if name == "len": return self.num_children(); @@ -77,7 +77,7 @@ class StdMapSynthProvider: return current.CreateChildAtOffset('['+str(index)+']',self.skip_size,self.data_type) # utility functions def node_ptr_value(self,node): - return int(node.GetValue(),0); + return node.GetValueAsUnsigned(0) def right(self,node): return node.GetChildMemberWithName("_M_right"); def left(self,node): diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py index ff0672b3928c..dc226902d1eb 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py @@ -5,9 +5,9 @@ class StdVectorSynthProvider: self.update() def num_children(self): - start_val = int(self.start.GetValue(),0) - finish_val = int(self.finish.GetValue(),0) - end_val = int(self.end.GetValue(),0) + start_val = self.start.GetValueAsUnsigned(0) + finish_val = self.finish.GetValueAsUnsigned(0) + end_val = self.end.GetValueAsUnsigned(0) # Before a vector has been constructed, it will contain bad values # so we really need to be careful about the length we return since # unitialized data can cause us to return a huge number. We need